珂朵莉树(ODT)

发布时间 2023-06-15 20:57:12作者: Flandreqwq

处理区间赋值问题的神器!

珂朵莉树的实现非常简单(baoli),建树时把区间的左右端点和权值作为一个节点 全扔到std::set(或者链表)中维护即可

split: 核心操作之一,将一段区间提取出来,在此之上进行一些操作

assign: 核心操作之二,也是降低珂朵莉树时间复杂度的重要操作,把一段区间推平赋值,减少大量节点个数,防止其退化成暴力

其他操作就非常暴力的进行就可以了

在网上查珂朵莉的时间复杂度大概是 \(n \log \log\) 的,常数很小,在随机数据下吊打线段树

但是,很多毒瘤的出题人会卡珂朵莉树,让区间赋值操作尽可能的少,这样就寄了

以这道题为例 CF896C (珂朵莉树起源)

大体操作:区间加 区间修改 求区间第k小 求区间x次幂

$my\,\ code$
#include<bits/stdc++.h>
#define read(a) scanf("%lld",&a)
#define read4(a,b,c,d) scanf("%lld%lld%lld%lld",&a,&b,&c,&d)
#define write(a) printf("%lld\n",a)
#define mem(a) memset(a,0,sizeof(a));
#define debug() puts("qwq qwq qwq qwq qwq");
#define Chtholly set <node>::iterator
using namespace std;
constexpr int N(1e5+5);
#define int long long
int n,m,seed,vmax,a[N];
inline int rnd(){
    int ret=seed;
    seed=(seed*7+13)%1000000007;
    return ret;
}
inline void make_data(int &op,int &l,int &r,int &x,int &y){
    op=(rnd()%4)+1;l=(rnd()%n)+1;r=(rnd()%n)+1;
    if(l>r) swap(l,r);
    if(op==3) x=(rnd()%(r-l+1))+1;
    else x=(rnd()%vmax)+1;
    if(op==4) y=(rnd()%vmax)+1;
}
struct node{
    int l,r;mutable int v;
    node()=default;
    node(int L,int R=0,int V=0):l(L),r(R),v(V){}
    bool operator<(const node &x)const{return l<x.l;}
};
set <node> odt;
Chtholly split(int pos){
    auto it=odt.lower_bound(pos);
    if(it!=odt.end()&&it->l==pos) return it;
    --it;if(it->r<pos) return odt.end(); 
	int l=it->l,r=it->r,v=it->v;
    odt.erase(it);odt.insert(node(l,pos-1,v));
    return odt.insert(node(pos,r,v)).first;
}
inline void assign(int l,int r,int v){
    auto it2=split(r+1),it1=split(l);
    odt.erase(it1,it2);
    odt.insert(node(l,r,v));
}
inline void add(int l,int r,int v){
    auto it2=split(r+1),it1=split(l);
    for(;it1!=it2;++it1){it1->v+=v;}
}
inline int kth(int l,int r,int k){
    auto it2=split(r+1),it1=split(l);
    vector <pair<int,int>> g;
    vector <pair<int,int>>().swap(g);
    for(;it1!=it2;++it1)
        g.push_back(make_pair(it1->v,it1->r-it1->l+1));
    sort(g.begin(),g.end());
    for(auto i:g){
        k-=i.second;
        if(k<=0) return i.first;
    }
    return -1;
}
inline int qpow(int a,int b,int p){
    int ret(1);a%=p;
    for(;b;a=a*a%p,b>>=1)
        if(b&1) ret=ret*a%p;
    return ret;
}
inline int sum(int l,int r,int x,int y){
    auto it2=split(r+1),it1=split(l);
    int ret(0);
    for(;it1!=it2;++it1)
        ret=(ret+qpow(it1->v,x,y)*(it1->r-it1->l+1)%y)%y;
    return ret;
}
signed main(){
    read4(n,m,seed,vmax);
    for(int i=1;i<=n;++i) a[i]=(rnd()%vmax)+1,odt.insert(node(i,i,a[i]));
    for(int i=1,op,l,r,x,y;i<=m;++i){
        make_data(op,l,r,x,y);
        switch(op){
            case 1:add(l,r,x);break;
            case 2:assign(l,r,x);break;
            case 3:write(kth(l,r,x));break;
            case 4:write(sum(l,r,x,y));break;
        } 
    }
    return 0;
}