ChthollyTree 模板

Posted bakacirno

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ChthollyTree 模板相关的知识,希望对你有一定的参考价值。

这种暴力又可爱的数据结构真的相当讨喜。如果题目中有操作是推平一段区间的话,那么它多半就是一道 ODT 的题。如果题目还保证了数据随机的话,那么恭喜你,ODT 一定可以简单高效的解决这个问题;但如果出题人卡数据的话,ODT 一定会 T 的飞起。
掌握 ODT 的难度是相当小的,只要理解到 split 和 assign 就好了,这两种操作也是相当简单。其他附加的操作也是在这两种操作的基础上怎么暴力怎么来。

两道板子题

CF896C

传送们
万恶之源,也是珂朵莉树的名字来源。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <set>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<LL,int> PLI;
const int N=1e5+10;
const int mod=1e9+7;
int n,m;
LL seed,vmax,a[N];

LL qpow(LL x,LL k,LL mod){
    LL res=1;x%=mod;
    while(k){
        if(k&1) res=res*x%mod;
        x=x*x%mod;k>>=1;
    }
    return res;
}

struct ChthollyTree{
    #define setit set<Node>::iterator
    struct Node{
        int l,r;
        mutable LL x;
        friend bool operator < (Node a,Node b){return a.l<b.l;}
    };
    set<Node> st;
    void build(){for(int i=1;i<=n+1;i++) st.insert(Node{i,i,a[i]});}
    setit split(int pos){
        setit it=st.lower_bound(Node{pos});
        if(it!=st.end()&&it->l==pos) return it;
        it--;
        int l=it->l,r=it->r;LL x=it->x;
        st.erase(it);
        st.insert(Node{l,pos-1,x});
        return st.insert(Node{pos,r,x}).first;
    }
    void assign(int l,int r,LL x){
        setit itl=split(l),itr=split(r+1);
        st.erase(itl,itr);
        st.insert(Node{l,r,x});
    }
    void add(int l,int r,LL v){
        setit itl=split(l),itr=split(r+1);
        for(setit it=itl;it!=itr;it++) it->x+=v;
    }
    LL getnum(int l,int r,int k){
        setit itl=split(l),itr=split(r+1);
        vector<pair<LL,int> > vp;
        for(setit it=itl;it!=itr;it++) vp.push_back({it->x,it->r-it->l+1});
        sort(vp.begin(),vp.end());
        for(pair<LL,int> p:vp){
            k-=p.second;
            if(k<=0) return p.first;
        }
        return -1;
    }
    LL asksum(int l,int r,int k,int mod){
        setit itl=split(l),itr=split(r+1);
        LL ans=0;
        for(setit it=itl;it!=itr;it++)
            ans=( ans+qpow(it->x,k,mod)*(it->r-it->l+1) )%mod;
        return ans;
    }
}odt;

int rnd(){
    int ret=seed;
    seed=(seed*7+13)%mod;
    return ret;
}

int main(){
    cin>>n>>m>>seed>>vmax;
    for(int i=1;i<=n;i++) a[i]=rnd()%vmax+1;
    odt.build();
    while(m--){
        int opt=rnd()%4+1,l=rnd()%n+1,r=rnd()%n+1,x,y;
        if(l>r) swap(l,r);
        if(opt==3) x=rnd()%(r-l+1)+1;
        else x=rnd()%vmax+1;
        if(opt==4) y=rnd()%vmax+1;
        if(opt==1) odt.add(l,r,x);
        else if(opt==2) odt.assign(l,r,x);
        else if(opt==3) printf("%lld
",odt.getnum(l,r,x));
        else if(opt==4) printf("%lld
",odt.asksum(l,r,x,y));
    }
    return 0;
}

2019太原理工新生预赛L题

传送门
稍微简单一些的典型的珂朵莉树的应用

#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <set>
#include <queue>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int n,m;
struct ChthollyTree{
    #define setit set<Node>::iterator
    struct Node{
        int l,r;
        mutable LL val;
        friend bool operator < (Node a,Node b){return a.l<b.l;}
    };
    set<Node> s;
    void build(){s.insert(Node{1,n,1});s.insert(Node{n+1,n+1,0});}
    setit split(int pos){
        setit it=s.lower_bound(Node{pos});
        if(it!=s.end()&&it->l==pos) return it;
        it--;
        int l=it->l,r=it->r,val=it->val;
        s.erase(it);
        s.insert(Node{l,pos-1,val});
        return s.insert(Node{pos,r,val}).first;
    }
    void assign(int l,int r,int val){
        setit itl=split(l),itr=split(r+1);
        s.erase(itl,itr);
        s.insert(Node{l,r,val});
    }
    void sumtor(int l,int r){
        setit itl=split(l),itr=split(r+1);
        LL sum=0;
        for(setit it=itl;it!=itr;it++) sum+=it->val*(it->r-it->l+1);
        assign(l,r-1,0);
        assign(r,r,sum);
    }
    int count(int l,int r){
        setit itl=split(l),itr=split(r+1);
        set<LL> st;
        int ans=0;
        for(setit it=itl;it!=itr;it++) if(it->val) st.insert(it->val);
        return st.size();
    }
}odt;

inline int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x*f;
}

int main(){
    n=read();m=read();
    odt.build();
    for(int i=1,opt,l,r;i<=m;i++){
        opt=read(),l=read(),r=read();
        if(opt==1) odt.assign(l,r,1);
        else if(opt==2) odt.sumtor(l,r);
        else if(opt==3) printf("%d
",odt.count(l,r));
    }
    return 0;
}

以上是关于ChthollyTree 模板的主要内容,如果未能解决你的问题,请参考以下文章

VSCode自定义代码片段1——vue主模板

VSCode自定义代码片段2——.vue文件的模板

VSCode自定义代码片段(vue主模板)

Eclipse 中的通用代码片段或模板

调用模板化成员函数:帮助我理解另一个 *** 帖子中的代码片段

vscode代码片段生成vue模板