欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > 我重生了,学会了珂朵莉树

我重生了,学会了珂朵莉树

2024/10/24 14:17:53 来源:https://blog.csdn.net/BestMonkey/article/details/140062411  浏览:    关键词:我重生了,学会了珂朵莉树

还玩线段树吗?

前言&注明

我好像一万年没更新了?

化学!!!!!!!!!!!!!!!!!!!(我发个电)
在这里插入图片描述

珂朵莉树貌似挺有用的?(做做熟练泼粪题就知道了)

还是要有参考资料的:

  • 珂朵莉树详解
    (From:CSDN,@Suryxin.)

先不启动,先说说珂朵莉树的起源

珂朵莉树原名老司机树(Old Driver Tree,ODT),由2017年一场CF比赛中提出的数据结构,因为题目背景主角是《末日时在做什么?有没有空?可以来拯救吗?》的主角珂朵莉,因此该数据结构被称为珂朵莉树。(引自珂朵莉树详解,我懒)

正片开始

啥是珂朵莉树?

通过 set 存放若干个用结构体表示的区间,每个区间的元素都是相同的一种较暴力的数据结构。

只要是涉及区间赋值操作的问题,就可以用珂朵莉树处理几乎任何有关区间信息的询问。(显然,前提是不会 TLE)

想要知道珂朵莉树怎么卡或者怎么会被卡,可见此。

所以,前置知识就来了

  • 关联式容器(set)(From:OI-Wiki)
  • mutable(自己找资料,感觉可以不学)

开始讲怎么写了

先扔出例题:Physical Education Lessons。

定义

之前说过珂朵莉树要用结构体存储区间,所以定义就是写一个结构体。

struct Project_KDL_Tree{int l,r;mutable int val;inline bool operator<(const Project_KDL_Tree&BlastMike)const{return l<BlastMike.l;}//重载运算符,按左端点排序Project_KDL_Tree(int L,int R=-1,int Val=0):l(L),r(R),val(Val){}
};

BlastMike:孩子们,我回来了。
在这里插入图片描述

Split

该函数实现我们要从 set 中的所有区间中找到我们要找的 n o w now now 所在的区间,并拆成两个区间 [ l , n o w − 1 ] [l, now - 1] [l,now1] [ n o w , r ] [now, r] [now,r], 使 n o w now now 作为一个区间的开头,返回该区间的迭代器。

inline S_It Split(int now){S_It it=KDL_Tree.lower_bound(Project_KDL_Tree(now));//找到now的迭代器if(it!=KDL_Tree.end()&&it->l==now)return it;//若这个迭代器的l是的now,直接返回--it;//若不是则在前一个里面int l=it->l,r=it->r,val=it->val;KDL_Tree.erase(it);//删掉该区间KDL_Tree.insert(Project_KDL_Tree(l,now-1,val));//重新放入区间[l,now-1]和[now,r]return KDL_Tree.insert(Project_KDL_Tree(now,r,val)).first;//返回以now为开头的迭代器
}
Assign Val

若不断进行split函数,会导致 TLE,所以我们需要一个区间合并操作即针对区间赋值的一个操作。

inline void Assign_Val(int l,int r,int val){S_It itr=Split(r+1),itl=Split(l);//先找到r+1的迭代器位置,再找l的迭代器位置,具体为什么可以看set的性质S_It it;for(it=itl;it!=itr;++it)Answer-=it->val*(it->r-it->l+1);//计算贡献,具体因题目而异KDL_Tree.erase(itl,itr);//删掉这一段KDL_Tree.insert(Project_KDL_Tree(l,r,val));//重新插入所需区间Answer+=val*(r-l+1);//计算贡献,具体因题目而异
}

为什么要找 r + 1 r+1 r+1?因为 set 删除的时候传参是左闭右开的。

Code
#include<bits/stdc++.h>
using namespace std;
const int Maxn=2e5+5;
struct Project_KDL_Tree{int l,r;mutable int val;inline bool operator<(const Project_KDL_Tree&BlastMike)const{return l<BlastMike.l;}Project_KDL_Tree(int L,int R=-1,int Val=0):l(L),r(R),val(Val){}
};
#define S_It set<Project_KDL_Tree>::iterator
set<Project_KDL_Tree>KDL_Tree;
long long Answer;
inline S_It Split(int now){S_It it=KDL_Tree.lower_bound(Project_KDL_Tree(now));if(it!=KDL_Tree.end()&&it->l==now)return it;--it;int l=it->l,r=it->r,val=it->val;KDL_Tree.erase(it);KDL_Tree.insert(Project_KDL_Tree(l,now-1,val));return KDL_Tree.insert(Project_KDL_Tree(now,r,val)).first;
}
inline void Assign_Val(int l,int r,int val){S_It itr=Split(r+1),itl=Split(l);S_It it;for(it=itl;it!=itr;++it)Answer-=it->val*(it->r-it->l+1);KDL_Tree.erase(itl,itr);KDL_Tree.insert(Project_KDL_Tree(l,r,val));Answer+=val*(r-l+1);
}
int n,m;
signed main(){ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);cin>>n>>m;Answer=n;KDL_Tree.insert(Project_KDL_Tree(1,n,1));for(register int i=1,l,r,val;i<=m;++i){cin>>l>>r>>val;Assign_Val(l,r,val-1);cout<<Answer<<endl;}return 0;
}

然后你就会了

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com