珂朵莉树
简介
珂朵莉树,一种暴力的数据结构,一般用来写对拍或者是骗分,在随机数据的情况下可以 $ AC $,对于大部分操作,珂朵莉树都可以用 $ \log n $ 到 $ \log \log n$ 的时间处理(当然是均摊)。
珂朵莉树维护的是一段相同的区间,区间左右点和值。用 $ set $ 维护,按左端点排序。
struct node{
int l,r;
mutable ll v;
//mutable极为重要,但是只需要记忆 影响set内值的改变
node (int lll=0,int rr=0,ll vv=0) {
l=lll;r=rr;v=vv;
}//
bool operator <(const node &i)const {
return l<i.l;
}
};
set <node> s;
操作split
用于拆分一个区间,区间的值可能改变,区间值的连续性就会发生破坏,这个时候就要把一个区间拆分成几个符合条件的区间。
//把区间[l,r]拆为[l,x-1]和[x,r]
IT split(int x){
IT it=s.lower_bound(node(x,0,0));//找到第一个左端点大于等于 x 的点
if(it!=s.end() && it->l==x) return it;//恰好就在l上就无须拆分
it--;//找到[l,r]
int L=it->l,R=it->r;ll V=it->v;
s.erase(it);//删掉原本的区间改为两个
s.insert(node(L,x-1,V));
return s.insert(node(x,R,V)).first;.first是指针地址
}
操作assign
推平操作,也就是区间赋值,拆分一下区间,例如操作区间 $ [l,r] $,就变成 $ [l,x] $ 和 $ [x,y] $ 以及 $ [y,r] $,把这三个区间都赋为目标值即可。
void assign(int l,int r,ll x){
IT itr=split(r+1),itl=split(l);//先右再左,否则r+1所在区间可能会被先删除,然后RE。
s.erase(itl,itr);
s.insert(node(l,r,x));
}
其余操作
都挺暴力的,都是暴力的取出去做。
void update(int l,int r,ll x){//区间加
IT itr=split(r+1),itl=split(l);
for(IT it=itl;it!=itr;it++)
it->v+=x;
}
ll rankk(int l,int r,int k) {//区间k小
vector<pll> p;
IT itr=split(r+1),itl=split(l);
p.clear();
for(IT it=itl;it!=itr;it++)
p.pb(make_pair(it->v,it->r - it->l + 1));
sort(p.begin(),p.end());
for(vector<pll >::iterator it=p.begin();it!=p.end();it++){
k-= it->second;
if(k<=0) return it->first;
}
return -inf;
}
ll pow_query(int l,int r,ll x,ll mod){//区间次幂和
IT itr=split(r+1),itl=split(l);
ll sum=0;
for(IT it=itl;it!=itr;it++)
sum = (sum + (ll)(it->r - it->l + 1) * pow(it->v, x, mod)) % mod;
return sum;
}
所以这东西真的暴力。珂朵莉树的时间复杂度主要取决于他的推平操作,需要足够次数的推平操作才能维护 $ \log $ 的复杂度。所以卡掉一个珂朵莉树只需要删去推平操作......

浙公网安备 33010602011771号