【模板整合计划】高阶数据结构

【模板整合计划】高阶数据结构


一:【并查集】

1.【路径压缩】

【模板】 并查集 \(\text{[P3367]}\)

#include<cstdio>
#define Re register int
const int N=1e4+3;
int n,x,y,T,op,fa[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline int find(Re x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main(){
    in(n),in(T);
    for(Re i=1;i<=n;++i)fa[i]=i;
    while(T--){
        in(op),in(x),in(y);
        if(op<2){if(find(x)!=find(y))fa[find(x)]=find(y);}
        else puts(find(x)==find(y)?"Y":"N");
    }
}

2.【按秩合并(启发式合并)】

【模板】 并查集 \(\text{[P3367]}\)

(1).【Deep】

#include<cstdio>
#define Re register int
const int N=1e4+3;
int n,x,y,T,op,fa[N],deep[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline int find(Re x){return x==fa[x]?x:find(fa[x]);}
inline void merge(Re x,Re y){
    x=find(x),y=find(y);
    if(x==y)return;
    if(deep[x]==deep[y])++deep[fa[x]=y];
    else if(deep[x]>deep[y])fa[y]=x;
    else fa[x]=y;
}
int main(){
    in(n),in(T);
    for(Re i=1;i<=n;++i)fa[i]=i;
    while(T--){
        in(op),in(x),in(y);
        if(op<2)merge(x,y);
        else puts(find(x)==find(y)?"Y":"N");
    }
}

(2).【Size】

#include<algorithm>
#include<cstdio>
#define Re register int
const int N=1e4+3;
int n,x,y,T,op,fa[N],size[N],deep[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline int find(Re x){return x==fa[x]?x:find(fa[x]);}
inline void merge(Re x,Re y){
    x=find(x),y=find(y);
    if(x==y)return;
    if(size[x]>size[y])std::swap(x,y);
    fa[x]=y,size[y]+=size[x];
}
int main(){
    in(n),in(T);
    for(Re i=1;i<=n;++i)fa[i]=i,size[i]=1;
    while(T--){
        in(op),in(x),in(y);
        if(op<2)merge(x,y);
        else puts(find(x)==find(y)?"Y":"N");
    }
}

3.【边带权】

银河英雄传说 \(\text{[P1196]}\)

#include<algorithm>
#include<cstdio>
#define Re register int
using namespace std;
const int N=3e4+3;
int n,x,y,T,op,fa[N],dis[N],size[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline int find(Re x){
    if(x==fa[x])return x;
    Re rt=find(fa[x]);
    dis[x]+=dis[fa[x]];
    return fa[x]=rt;
}
inline void merge(Re x,Re y){
    x=find(x),y=find(y);
    fa[x]=y,dis[x]=size[y];
    size[y]+=size[x];
}
int main(){
    in(T);
    for(Re i=1;i<=30000;++i)fa[i]=i,size[i]=1;
    while(T--){
        scanf(" %c",&op),in(x),in(y);
        if(op=='M')merge(x,y);
        else printf("%d\n",find(x)!=find(y)?-1:abs(dis[x]-dis[y])-1);
    }
}

4.【扩展域】

食物链 \(\text{[P2024]}\)

#include<cstdio>
#define Re register int
const int N=5e4+3;
int n,a,b,c,T,b1,b2,b3,c1,c2,c3,ans,fa[N*3];
inline void in(Re &x){
    Re fu=0;x=0;char ch=getchar();
    while(ch<'0'||ch>'9')fu|=ch=='-',ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=fu?-x:x;
}
inline int find(Re x){return x==fa[x]?x:fa[x]=find(fa[x]);}
// fa[x],b1,c1 食物 
// fa[x+n],b2,c2 天敌 
// fa[x+2*n],b3,c3 同类 
int main(){
    in(n),in(T);
    for(Re i=1;i<=n;++i)fa[i]=i,fa[i+n]=i+n,fa[i+2*n]=i+2*n;
    while(T--){
        in(a),in(b),in(c);
        if(b>n||c>n){++ans;continue;}
        if(a>1){//b吃c 
            if(b==c){++ans;continue;};
            //食物        天敌          同类 
            b1=find(b),b2=find(b+n),b3=find(b+2*n);
            c1=find(c),c2=find(c+n),c3=find(c+2*n);
            if(b2==c3||b3==c1||b3==c3){++ans;continue;};
            fa[b1]=fa[c3],fa[c2]=fa[b3],fa[b2]=fa[c1]; 
        }
        else{//b,c是同类 
            //食物        天敌          同类 
            b1=find(b),b2=find(b+n),b3=find(b+2*n);
            c1=find(c),c2=find(c+n),c3=find(c+2*n);
            if(b1==c3||b2==c3||c1==b3||c2==b3){++ans;continue;};
            fa[b3]=fa[c3],fa[b1]=fa[c1],fa[b2]=fa[c2];
        }
    }
    printf("%d",ans);
}

二:【树状数组】

【模板整合计划】高阶数据结构—树状数组


三:【线段树】

【模板整合计划】高阶数据结构—线段树


四:【分块】

【模板整合计划】高阶数据结构—分块


五:【可并堆】

1.【左偏树】

【模板】 左偏树(可并堆)\(\text{[P3377]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define Re register int
using namespace std;
const int N=1e5+5;
int n,x,y,T,op,A[N];
inline void in(Re &x){
    Re fu=0;x=0;char ch=getchar();
    while(ch<'0'||ch>'9')fu|=ch=='-',ch=getchar();
    while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=fu?-x:x;
}
struct Leftist_Tree{
    int fa[N],pl[N],pr[N],dis[N];
    inline int merge(Re x,Re y){
        if(!x||!y)return x+y;
        if(A[x]>A[y]||(A[x]==A[y]&&x>y))swap(x,y);
        pr[x]=merge(pr[x],y);
        if(dis[pl[x]]<dis[pr[x]])swap(pl[x],pr[x]);
        dis[x]=dis[pr[x]]+1;
        if(pl[x])fa[pl[x]]=x;
        if(pr[x])fa[pr[x]]=x;
        return x;
    }
    inline int top(Re x){return fa[x]==x?x:fa[x]=top(fa[x]);}
    inline void pop(Re x){
        A[x]=-1,fa[pl[x]]=pl[x],fa[pr[x]]=pr[x];
        fa[x]=merge(pl[x],pr[x]),pl[x]=pr[x]=0;
    }
}T1;
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(T);
    for(Re i=1;i<=n;++i)in(A[i]),T1.fa[i]=i;
    while(T--){
        in(op),in(x);
        if(op&1){
            in(y);
            if(A[x]!=-1&&A[y]!=-1){
                x=T1.top(x),y=T1.top(y);
                if(x!=y)T1.merge(x,y);
            }
        }
        else if(A[x]==-1)puts("-1");
        else printf("%d\n",A[T1.top(x)]),T1.pop(T1.top(x));
    }
}

五:【CDQ 分治】

【模板】 三维偏序(陌上花开)\(\text{[P3810]}\)

#include<algorithm>
#include<cstdio>
#define Re register int
using std::sort;
const int N=1e5+5,K=2e5+5;
int n,m,k,C[K],ans[N];
struct QAQ{int a,b,c,cnt,ans;}a[N],Q[N];//cnt为副本,ans为严格小于它的点的数量
inline void in(Re &x){
    int fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
inline bool cmp1(QAQ p,QAQ o){return p.a!=o.a?p.a<o.a:(p.b!=o.b?p.b<o.b:p.c<o.c);}
inline bool cmp2(QAQ p,QAQ o){return p.b<o.b;}
inline void add(Re x,Re v){while(x<=k)C[x]+=v,x+=x&-x;}
inline int ask(Re x){
    Re ans=0;
    while(x)ans+=C[x],x-=x&-x;
    return ans;
}
inline void CDQ(Re L,Re R){
    if(L==R)return;
    Re mid=L+R>>1;
    CDQ(L,mid),CDQ(mid+1,R);
    sort(Q+L,Q+mid+1,cmp2),sort(Q+mid+1,Q+R+1,cmp2);
    Re j=L;
    for(Re i=mid+1;i<=R;++i){
        while(j<=mid&&Q[j].b<=Q[i].b)add(Q[j].c,Q[j].cnt),++j;
        Q[i].ans+=ask(Q[i].c);
    }
    for(Re i=L;i<j;++i)add(Q[i].c,-Q[i].cnt);//这里是小于j而不是mid 
}
int main(){
    in(n),in(k);
    for(Re i=1;i<=n;++i)in(a[i].a),in(a[i].b),in(a[i].c);
    sort(a+1,a+n+1,cmp1);
    for(Re i=1;i<=n;++i){
        if(i>2&&a[i].a==a[i-1].a&&a[i].b==a[i-1].b&&a[i].c==a[i-1].c)++Q[m].cnt;
        else Q[++m]=a[i],Q[m].cnt=1;
    }
    CDQ(1,m);
    for(Re i=1;i<=m;++i)ans[Q[i].ans+Q[i].cnt-1]+=Q[i].cnt;
    for(Re i=0;i<n;++i)printf("%d\n",ans[i]);
}

六:【整体二分】

1.【整体二分】

【模板】 \(\text{K}\) 大数查询\(\text{[ZJOI2013] [P3332]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define Re register int
#define LL long long
using namespace std;
const int N=5e4+3,M=5e4+3,inf=1e9;
int n,x,T,Ans[M];
struct QAQ{int l,r,op,id;LL k;}Q[N+M],Q1[N+M],Q2[N+M];
inline void in(Re &x){
    int fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
struct Segment_Tree{
    #define pl p<<1
    #define pr p<<1|1
    #define Mid (L+R>>1)
    struct QAQ{int CL,add;LL S;}tr[N<<2];
    inline void pushup(Re p){tr[p].S=tr[pl].S+tr[pr].S;}
    inline void updata(Re p,Re L,Re R,Re v){tr[p].S+=v*(R-L+1),tr[p].add+=v;}
    inline void updata_(Re p){tr[p].add=tr[p].S=0,tr[p].CL=1;}
    inline void pushdown(Re p,Re L,Re R){
        if(tr[p].CL)updata_(pl),updata_(pr),tr[p].CL=0;
        if(tr[p].add)updata(pl,L,Mid,tr[p].add),updata(pr,Mid+1,R,tr[p].add),tr[p].add=0;
    }
    inline void change(Re p,Re L,Re R,Re l,Re r,Re v){
        if(l<=L&&R<=r){updata(p,L,R,v);return;}
        pushdown(p,L,R);
        if(l<=Mid)change(pl,L,Mid,l,r,v);
        if(r>Mid)change(pr,Mid+1,R,l,r,v);
        pushup(p);
    }
    inline LL ask(Re p,Re L,Re R,Re l,Re r){
        if(l<=L&&R<=r)return tr[p].S;
        LL ans=0;pushdown(p,L,R);
        if(l<=Mid)ans+=ask(pl,L,Mid,l,r);
        if(r>Mid)ans+=ask(pr,Mid+1,R,l,r);
        return ans;
    }
}T1;
inline void sakura(Re l,Re r,Re L,Re R){
    if(L>R)return;
    if(l==r){
        for(Re i=L;i<=R;++i)if(Q[i].op>1)Ans[Q[i].id]=l;
        return;
    }
    Re mid=l+r>>1,m1=0,m2=0;
    for(Re i=L;i<=R;++i)
        if(Q[i].op&1){
            if(Q[i].k<=mid)Q1[++m1]=Q[i];
            else Q2[++m2]=Q[i],T1.change(1,1,n,Q[i].l,Q[i].r,1);
        }
        else{
            LL tmp=T1.ask(1,1,n,Q[i].l,Q[i].r);
            if(Q[i].k<=tmp)Q2[++m2]=Q[i];
            else Q[i].k-=tmp,Q1[++m1]=Q[i];
        }
    T1.updata_(1);
    for(Re i=1;i<=m1;++i)Q[L+i-1]=Q1[i];
    for(Re i=1;i<=m2;++i)Q[L+m1+i-1]=Q2[i];
    sakura(l,mid,L,L+m1-1);
    sakura(mid+1,r,L+m1,R);
}
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(T);
    for(Re i=1;i<=T;++i){
        in(Q[i].op),in(Q[i].l),in(Q[i].r),in(x),Q[i].k=x;
        if(Q[i].op>1)Q[i].id=++Ans[0];
    }
    sakura(-n,n,1,T);
    for(Re i=1;i<=Ans[0];++i)printf("%d\n",Ans[i]);
}

2.【静态区间第 K 小】

【模板】 可持久化线段树 \(1\)(主席树)\(\text{[P3834]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define Re register int
#define LL long long
using namespace std;
const int N=2e5+3,M=2e5+3,inf=1e9;
int n,x,y,z,T,cnt,Ans[M];char op;
struct QAQ{int l,r,k,op,id;}Q[N+M],Q1[N+M],Q2[N+M];
inline void in(Re &x){
    int fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
struct BIT{
    int C[N];
    inline void add(Re x,Re v){while(x<=n)C[x]+=v,x+=x&-x;}
    inline int ask_(Re x){Re ans=0;while(x)ans+=C[x],x-=x&-x;return ans;}
    inline int ask(Re l,Re r){return ask_(r)-ask_(l-1);}
}T1;
inline void sakura(Re l,Re r,Re L,Re R){
    if(L>R)return;
    if(l==r){
        for(Re i=L;i<=R;++i)if(Q[i].op>1)Ans[Q[i].id]=l;
        return;
    }
    Re mid=l+r>>1,m1=0,m2=0;
    for(Re i=L;i<=R;++i)
        if(Q[i].op&1){
            if(Q[i].k<=mid)Q1[++m1]=Q[i],T1.add(Q[i].id,1);
            else Q2[++m2]=Q[i];
        }
        else{
            Re tmp=T1.ask(Q[i].l,Q[i].r);
            if(Q[i].k<=tmp)Q1[++m1]=Q[i];
            else Q[i].k-=tmp,Q2[++m2]=Q[i];
        }
    for(Re i=1;i<=m1;++i)if(Q1[i].op&1)T1.add(Q1[i].id,-1);
    for(Re i=1;i<=m1;++i)Q[L+i-1]=Q1[i];
    for(Re i=1;i<=m2;++i)Q[L+m1+i-1]=Q2[i];
    sakura(l,mid,L,L+m1-1);
    sakura(mid+1,r,L+m1,R);
}
int main(){
    freopen("123.txt","r",stdin);
    in(n),in(T);
    for(Re i=1;i<=n;++i)in(x),Q[++cnt]=(QAQ){0,0,x,1,i};
    for(Re i=1;i<=T;++i)in(x),in(y),in(z),Q[++cnt]=(QAQ){x,y,z,2,i};
    sakura(-inf,inf,1,cnt);
    for(Re i=1;i<=T;++i)printf("%d\n",Ans[i]);
}

3.【动态区间第 K 小】

【模板】 \(\text{Dynamic Rankings [P3834]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#define Re register int
#define LL long long
using namespace std;
const int N=1e5+3,M=1e5+3,inf=1e9;
int n,x,y,z,T,cnt,a[N],Ans[M];char op;
struct QAQ{int l,r,k,op,id;}Q[N+M*2],Q1[N+M*2],Q2[N+M*2];
inline void in(Re &x){
    int fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
struct BIT{
    int C[N];
    inline void add(Re x,Re v){while(x<=n)C[x]+=v,x+=x&-x;}
    inline int ask_(Re x){Re ans=0;while(x)ans+=C[x],x-=x&-x;return ans;}
    inline int ask(Re l,Re r){return ask_(r)-ask_(l-1);}
}T1;
inline void sakura(Re l,Re r,Re L,Re R){
    if(L>R)return;
    if(l==r){
        for(Re i=L;i<=R;++i)if(Q[i].op>1)Ans[Q[i].id]=l;
        return;
    }
    Re mid=l+r>>1,m1=0,m2=0;
    for(Re i=L;i<=R;++i)
        if(Q[i].op&1){
            if(Q[i].l<=mid)Q1[++m1]=Q[i],T1.add(Q[i].id,Q[i].r);
            else Q2[++m2]=Q[i];
        }
        else{
            Re tmp=T1.ask(Q[i].l,Q[i].r);
            if(Q[i].k<=tmp)Q1[++m1]=Q[i];
            else Q[i].k-=tmp,Q2[++m2]=Q[i];
        }
    for(Re i=1;i<=m1;++i)if(Q1[i].op&1)T1.add(Q1[i].id,-Q1[i].r);
    for(Re i=1;i<=m1;++i)Q[L+i-1]=Q1[i];
    for(Re i=1;i<=m2;++i)Q[L+m1+i-1]=Q2[i];
    sakura(l,mid,L,L+m1-1);
    sakura(mid+1,r,L+m1,R);
}
int main(){
    freopen("123.txt","r",stdin);
    in(n),in(T);
    for(Re i=1;i<=n;++i)in(a[i]),Q[++cnt]=(QAQ){a[i],1,0,1,i};
    while(T--){
        scanf(" %c",&op),in(x),in(y);
        if(op=='C')Q[++cnt]=(QAQ){a[x],-1,0,1,x},Q[++cnt]=(QAQ){a[x]=y,1,0,1,x};
        else in(z),Q[++cnt]=(QAQ){x,y,z,2,++Ans[0]};
    }
    sakura(-inf,inf,1,cnt);
    for(Re i=1;i<=Ans[0];++i)printf("%d\n",Ans[i]);
}

七:【莫队】

1.【静态莫队】

【模板】 \(\text{D-query}\) \(\text{[SP3267]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define Re register int
using namespace std;
const int N=3e4+3,M=2e5+3;
int n,T,BL,ans,A[N],cnt[1000003],Ans[M];
struct Query{
    int l,r,id;
    inline bool operator<(const Query &O)const{
        Re B1=l/BL,B2=O.l/BL;
        return B1!=B2?B1<B2:((B1&1)?r<O.r:r>O.r);
    }
}Q[M];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline void add(Re x){ans+=!cnt[x]++;}
inline void del(Re x){ans-=!--cnt[x];}
int main(){
    in(n),BL=sqrt(n)+1;
    for(Re i=1;i<=n;++i)in(A[i]);
    in(T);
    for(Re i=1;i<=T;++i)in(Q[i].l),in(Q[i].r),Q[i].id=i;
    sort(Q+1,Q+T+1);Re nowL=1,nowR=0;
    for(Re i=1;i<=T;++i){
        while(nowR<Q[i].r)add(A[++nowR]);
        while(nowR>Q[i].r)del(A[nowR--]);
        while(nowL>Q[i].l)add(A[--nowL]);
        while(nowL<Q[i].l)del(A[nowL++]);
        Ans[Q[i].id]=ans;
    }
    for(Re i=1;i<=T;++i)printf("%d\n",Ans[i]);
}

2.【带修莫队】

【模板】 数颜色 / 维护队列 \(\text{[P1903]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define Re register int
using namespace std;
const int N=2e5+3,M=2e5+3,INF=1e6+3;
int n,x,y,T,TQ,TC,BL,ans,a[N],Ans[M],cnt[INF];char op;
struct Query{
    int l,r,id,time;
    inline bool operator<(const Query &O)const{
        Re B1=l/BL,B2=O.l/BL,B3=r/BL,B4=O.r/BL;
        return B1!=B2?B1<B2:(B3!=B4?B3<B4:time<O.time);
    }
}Q[N];
struct Change{int w,co;}C[N];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
inline void add(Re x){ans+=!cnt[x]++;}
inline void del(Re x){ans-=!--cnt[x];}
int main(){
    in(n),in(T),BL=pow(n,2.0/3.0);
    for(Re i=1;i<=n;++i)in(a[i]);
    for(Re i=1;i<=T;++i){
        scanf(" %c",&op);
        in(x),in(y);
        if(op=='Q')++TQ,Q[TQ]=(Query){x,y,TQ,TC};
        else C[++TC]=(Change){x,y};
    }
    sort(Q+1,Q+TQ+1);
    Re nowL=1,nowR=0,nowT=0;
    for(Re i=1;i<=TQ;++i){
        while(nowL<Q[i].l)del(a[nowL++]);
        while(nowL>Q[i].l)add(a[--nowL]);
        while(nowR>Q[i].r)del(a[nowR--]);
        while(nowR<Q[i].r)add(a[++nowR]);
        while(nowT<Q[i].time){
            Re w=C[++nowT].w;
            if(nowL<=w&&w<=nowR)del(a[w]),add(C[nowT].co);
            swap(a[w],C[nowT].co);
        }
        while(nowT>Q[i].time){
            Re w=C[nowT].w;
            if(nowL<=w&&w<=nowR)del(a[w]),add(C[nowT].co);
            swap(a[w],C[nowT--].co);
        }
        Ans[Q[i].id]=ans;
    }
    for(Re i=1;i<=TQ;++i)printf("%d\n",Ans[i]);
}

3.【树上静态莫队】

【模板】 \(\text{COT2 - Count on a tree II [SP10707]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define Re register int
using namespace std;
const int N=4e4+3,M=1e5+3,INF=1e6+3,logN=16;
int n,m,o,x,y,T,BL,id_O,b[N],A[N],B[N<<1],head[N],last[N],first[N];
struct QAQ{int to,next;}a[N<<1];
inline void add(Re x,Re y){a[++o].to=y,a[o].next=head[x],head[x]=o;}
inline void in(Re &x){
    Re fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
struct LCA{
    int deep[N],ant[N][20];
    inline void dfs(Re x,Re fa){
        first[B[++B[0]]=x]=++id_O;
        deep[x]=deep[ant[x][0]=fa]+1;
        for(Re i=1;(1<<i)<=deep[x];++i)ant[x][i]=ant[ant[x][i-1]][i-1];
        for(Re i=head[x];i;i=a[i].next)if(a[i].to!=fa)dfs(a[i].to,x);
        last[B[++B[0]]=x]=++id_O;
    }
    inline int lca(Re x,Re y){
        if(deep[x]<deep[y])swap(x,y);
        for(Re i=logN;i>=0;--i)if(deep[ant[x][i]]>=deep[y])x=ant[x][i];
        if(x==y)return x;
        for(Re i=logN;i>=0;--i)if(ant[x][i]!=ant[y][i])x=ant[x][i],y=ant[y][i];
        return ant[x][0];
    }
}T1;
struct Query{
    int l,r,id,lca;
    inline bool operator<(const Query &O)const{
        Re B1=l/BL,B2=O.l/BL;
        return B1!=B2?B1<B2:((B1&1)?r<O.r:r>O.r);
    }
}Q[M];
int ans,vis[N<<1],Ans[M],cnt[INF];
inline void change(Re x){
    vis[x]?ans-=!--cnt[A[x]]:ans+=!cnt[A[x]]++,vis[x]^=1;
}
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(T),BL=sqrt(n<<1);
    for(Re i=1;i<=n;++i)in(A[i]),b[i]=A[i];
    sort(b+1,b+n+1),m=unique(b+1,b+n+1)-b-1;
    for(Re i=1;i<=n;++i)A[i]=lower_bound(b+1,b+m+1,A[i])-b;
    m=n-1;while(m--)in(x),in(y),add(x,y),add(y,x);
    T1.dfs(1,0);
    for(Re i=1;i<=T;++i){
        in(x),in(y);Re lca=T1.lca(x,y);
        if(first[x]>first[y])swap(x,y);
        if(lca==x)Q[i]=(Query){first[x],first[y],i,0};
        else Q[i]=(Query){last[x],first[y],i,lca};
    }
    sort(Q+1,Q+T+1);
    Re nowL=1,nowR=0;
    for(Re i=1;i<=T;++i){
        Re L=Q[i].l,R=Q[i].r,lca=Q[i].lca;
        while(nowL<L)change(B[nowL++]);
        while(nowL>L)change(B[--nowL]);
        while(nowR>R)change(B[nowR--]);
        while(nowR<R)change(B[++nowR]);
        if(lca)change(lca);
        Ans[Q[i].id]=ans;
        if(lca)change(lca);
    }
    for(Re i=1;i<=T;++i)printf("%d\n",Ans[i]);
}

4.【树上带修莫队】

【模板】 糖果公园 \(\text{[WC2013]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define Re register int
using namespace std;
const int N=1e5+3,M=1e5+3,logN=17;
int n,m,x,y,o,T,op,id_O,A[N],V[N],W[N],B[N],head[N],last[N],first[N];
struct QAQ{int to,next;}a[N<<1];
inline void add(Re x,Re y){a[++o].to=y,a[o].next=head[x],head[x]=o;}
inline void in(Re &x){
    Re fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
struct LCA{
    int deep[N],ant[N][20];
    inline void dfs(Re x,Re fa){
        first[B[++B[0]]=x]=++id_O;
        deep[x]=deep[ant[x][0]=fa]+1;
        for(Re i=1;(1<<i)<=deep[x];++i)ant[x][i]=ant[ant[x][i-1]][i-1];
        for(Re i=head[x];i;i=a[i].next)if(a[i].to!=fa)dfs(a[i].to,x);
        last[B[++B[0]]=x]=++id_O;
    }
    inline int lca(Re x,Re y){
        if(deep[x]<deep[y])swap(x,y);
        for(Re i=logN;i>=0;--i)if(deep[ant[x][i]]>=deep[y])x=ant[x][i];
        if(x==y)return x;
        for(Re i=logN;i>=0;--i)if(ant[x][i]!=ant[y][i])x=ant[x][i],y=ant[y][i];
        return ant[x][0];
    }
}T1;
int BL,TQ,TC,vis[N],cnt[N];LL ans,Ans[M];
struct Query{
    int l,r,id,lca,time;
    inline bool operator<(const Query &O)const{
        Re B1=l/BL,B2=O.l/BL,B3=r/BL,B4=O.r/BL;
        return B1!=B2?B1<B2:(B3!=B4?B3<B4:time<O.time);
    }
}Q[M];
struct Change{int w,co;}C[M];
inline void change(Re x){
    vis[x]?ans-=(LL)V[A[x]]*W[cnt[A[x]]--]:ans+=(LL)V[A[x]]*W[++cnt[A[x]]],vis[x]^=1;
}
int main(){
    freopen("123.txt","r",stdin);
    in(n),in(m),in(T),BL=pow(n<<1,2.0/3.0);
    for(Re i=1;i<=m;++i)in(V[i]);
    for(Re i=1;i<=n;++i)in(W[i]);
    for(Re i=1;i<n;++i)in(x),in(y),add(x,y),add(y,x);
    for(Re i=1;i<=n;++i)in(A[i]);
    T1.dfs(1,0);
    for(Re i=1;i<=T;++i){
        in(op),in(x),in(y);
        if(op){
            Re lca=T1.lca(x,y);
            if(first[x]>first[y])swap(x,y);
            if(lca==x)++TQ,Q[TQ]=(Query){first[x],first[y],TQ,0,TC};
            else ++TQ,Q[TQ]=(Query){last[x],first[y],TQ,lca,TC};
        }
        else C[++TC]=(Change){x,y};
    }
    sort(Q+1,Q+TQ+1);
    Re nowL=1,nowR=0,nowT=0;
    for(Re i=1;i<=TQ;++i){
        Re L=Q[i].l,R=Q[i].r,T=Q[i].time,lca=Q[i].lca;
        while(nowL<L)change(B[nowL++]);
        while(nowL>L)change(B[--nowL]);
        while(nowR>R)change(B[nowR--]);
        while(nowR<R)change(B[++nowR]);
        while(nowT<T){
            Re w=C[++nowT].w;
            if(vis[w])change(w),swap(A[w],C[nowT].co),change(w);
            else swap(A[w],C[nowT].co);
        }
        while(nowT>T){
            Re w=C[nowT].w;
            if(vis[w])change(w),swap(A[w],C[nowT].co),change(w);
            else swap(A[w],C[nowT].co);
            --nowT;
        }
        if(lca)change(lca);
        Ans[Q[i].id]=ans;
        if(lca)change(lca);
    }
    for(Re i=1;i<=TQ;++i)printf("%lld\n",Ans[i]);
}

5.【回滚莫队】

【模板】 歴史の研究 \(\text{[AT1219]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define Re register int
using namespace std;
const int N=1e5+3,M=1e5+3;
int n,m,T,BL,BLN,A[N],b[N],Li[325],Ri[325],cnt[N],cnt_[N],belong[N];LL Ans[M];
struct Query{
    int l,r,id;
    inline bool operator<(const Query &O)const{
        Re B1=belong[l],B2=belong[O.l];
        return B1!=B2?B1<B2:r<O.r;
    }
}Q[M];
inline void in(Re &x){
    Re fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
int main(){
//    freopen("123.txt","r",stdin);
    in(n),in(T),BL=sqrt(n)+1,BLN=n/BL+1;
    for(Re i=1;i<=BLN;++i){
        Li[i]=(i-1)*BL+1,Ri[i]=min(i*BL,n);
        for(Re j=Li[i];j<=Ri[i];++j)belong[j]=i;
    }
    for(Re i=1;i<=n;++i)in(A[i]),b[i]=A[i];
    sort(b+1,b+n+1),m=unique(b+1,b+n+1)-b-1;
    for(Re i=1;i<=n;++i)A[i]=lower_bound(b+1,b+m+1,A[i])-b;
    for(Re i=1;i<=T;++i)in(Q[i].l),in(Q[i].r),Q[i].id=i;
    sort(Q+1,Q+T+1);Re i=1;
    for(Re p=1;p<=BLN;++p){
        Re nowL=Ri[p]+1,nowR=Ri[p];LL ans=0;
        memset(cnt,0,sizeof(cnt));
        while(belong[Q[i].l]==p){
            Re L=Q[i].l,R=Q[i].r;
            if(belong[L]==belong[R]){
                LL tmp=0;
                for(Re j=L;j<=R;++j)cnt_[A[j]]=0;
                for(Re j=L;j<=R;++j)++cnt_[A[j]],tmp=max(tmp,(LL)b[A[j]]*cnt_[A[j]]);
                Ans[Q[i].id]=tmp;
            }
            else{
                while(nowR<R)cnt[A[++nowR]]++,ans=max(ans,(LL)b[A[nowR]]*cnt[A[nowR]]);
                LL tmp=ans;
                while(nowL>L)cnt[A[--nowL]]++,tmp=max(tmp,(LL)b[A[nowL]]*cnt[A[nowL]]);
                Ans[Q[i].id]=tmp;
                while(nowL<Ri[p]+1)--cnt[A[nowL++]];
            }
            ++i;
        }
    }
    for(Re i=1;i<=T;++i)printf("%lld\n",Ans[i]);
}

八:【平衡树】

1.【Treap】

【模板】 普通平衡树 \(\text{[P3369]}\)

#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#define Re register int
#define pl tr[p].lp
#define pr tr[p].rp
#define pv tr[p].v
using namespace std;
const int N=1e5+5,inf=2e9;
int a,b,o,T,root;
inline void in(Re &x){
    int fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
struct Treap{int v,rd,lp,rp,cnt,size;}tr[N];//cnt为该节点处这个数v的个数
inline void pushup(Re p){tr[p].size=tr[p].cnt+tr[pl].size+tr[pr].size;}//更新节点空间信息
inline void lturn(Re &p){//左旋
    Re q=pr;pr=tr[q].lp,tr[q].lp=p;//颠倒父子关系
    pushup(p),pushup(p=q);//先push(p)再push(q)并拉好最上面的线
//拉线:p=q。这里的p经过无数次取地址符反复调用而来,回溯至初相当于tr[?].lp或者tr[?].rp
}
inline void rturn(Re &p){//右旋
    Re q=pl;pl=tr[q].rp,tr[q].rp=p;//颠倒父子关系
    pushup(p),pushup(p=q);//先push(p)再push(q)并拉好最上面的线
}
inline void insert(Re &p,Re x){
    if(!p){tr[p=++o].v=x,tr[p].cnt=tr[p].size=1,tr[p].rd=rand();return;}
    ++tr[p].size;
    if(x==pv)++tr[p].cnt;
    else if(x<pv){
        insert(pl,x);
        if(tr[pl].rd<tr[p].rd)rturn(p);//小跟堆
    }
    else{
        insert(pr,x);
        if(tr[pr].rd<tr[p].rd)lturn(p);//小跟堆
    }
}
inline void del(Re &p,Re x){
    if(!p)return;
    if(x<pv)--tr[p].size,del(pl,x);
    else if(x>pv)--tr[p].size,del(pr,x);
    else{
        if(tr[p].cnt>1)--tr[p].cnt,--tr[p].size;//如果这个数的个数不止一个,直接减一轻松退出
        else{//否则需要删除该节点
            if(pl*pr==0)p=pl+pr;
//其中一个儿子为空,直接指向这个不空的,那么访问时就可以直接跳过节点p,相当于达到了删除p的目的
//如果都为空,相当于把p赋值成了0
//否则的话,先调整好两个儿子的次序,然后将p丢到一边并继续删除操作
            else if(tr[pl].rd<tr[pr].rd)rturn(p),del(p,x);
            else lturn(p),del(p,x);
        }
    }
}
inline int ask_level(Re p,Re x){//查询数x的排名(保证存在x)。
//    if(!p)return 0;//如果没找到这个数
    if(x==pv)return tr[pl].size+1;//找到了这个数
    else return x<pv?ask_level(pl,x):tr[p].cnt+tr[pl].size+ask_level(pr,x);
}
inline int ask_v(Re p,Re x){//查询排名为x的数
//    if(!p)return 0;//如果没找到这个数
    if(x<=tr[pl].size)return ask_v(pl,x);
    else{
        Re tmp=tr[pl].size+tr[p].cnt;
        return x<=tmp?pv:ask_v(pr,x-tmp);
    }
}
inline int ask_pri(Re p,Re x){//查询x的前驱
    if(!p)return -inf;
    if(x<=pv)return ask_pri(pl,x);
    else return max(pv,ask_pri(pr,x));
}
inline int ask_nex(Re p,Re x){//查询x的后继
    if(!p)return inf;
    if(x>=pv)return ask_nex(pr,x);
    else return min(pv,ask_nex(pl,x));
}
int main(){
    srand((int)time(NULL));
    in(T);
    while(T--){
        in(a),in(b);
        if(a==1)insert(root,b);
        if(a==2)del(root,b);
        if(a==3)printf("%d\n",ask_level(root,b));
        if(a==4)printf("%d\n",ask_v(root,b));
        if(a==5)printf("%d\n",ask_pri(root,b));
        if(a==6)printf("%d\n",ask_nex(root,b));
    }
}

2.【FHQ Treap】

3.【伸展树 (Splay)】

(1).【维护堆】

【模板】 普通平衡树 \(\text{[P3369]}\)

#include<algorithm>
#include<cstdio>
#define Re register int
#define pl tr[p].ps[0]
#define pr tr[p].ps[1]
#define pf tr[p].fa
#define pv tr[p].v
using namespace std;
const int N=1e5+5,inf=2e9;
int T,a,b,n,o,root;
struct Splay{int v,fa,ps[2],cnt,size;}tr[N];
inline void in(Re &x){
    int fu=0;x=0;char c=getchar();
    while(c<'0'||c>'9')fu|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=fu?-x:x;
}
inline void pushup(Re p){if(!p)return;/*这里必需要加判断return,否则会崩死*/tr[p].size=tr[p].cnt+tr[pl].size+tr[pr].size;}
inline void connect(Re p,Re f,Re o){tr[tr[p].fa=f].ps[o]=p;}//让p成为f的o儿子
inline int which(Re p){return tr[pf].ps[1]==p;}//查询p是哪个儿子
inline void rotate(Re p){//Treap是把p往下拉,这里是把p往上拉到pf的头上去
    Re y=pf,ys=which(p);//【y】x的父结点。【ys】x是它父亲的哪个儿子
    Re R=tr[y].fa,Rs=which(y);//【R】y的父亲。【Rs】y是它父亲的哪个儿子
    Re B=tr[p].ps[ys^1];//p的儿子中与pf同方向的点(需要将其连到y上)
    connect(B,y,ys),connect(y,p,ys^1),connect(p,R,Rs);//改线
    pushup(y),pushup(p);//p被拉到了y头上去,先02更新y,再更新p
}
inline void Splay(Re p){//无论如何都一定要一次旋两下,NOI的巨毒瘤数据会卡这里
    for(Re fa;fa=pf;rotate(p))
        if(tr[fa].fa)rotate(which(p)==which(fa)?fa:p);
    root=p;
//线性卡单旋,人字形卡双旋
}
inline void New(Re x,Re fa){//建一个新点x并接到 fa下面
    tr[++o].v=x,tr[o].fa=fa,tr[o].cnt=tr[o].size=1;
    if(fa)tr[fa].ps[tr[fa].v<x]=o;
}
inline void insert(Re x){
    if(!root){New(x,0);root=o;return;}//空树则直接简单接入
    int p=root,fa=0;
    while(1){
        if(x==pv){++tr[p].cnt,pushup(p),pushup(fa),Splay(p);break;}//发现了副本
        fa=p,p=tr[p].ps[pv<x];//继续往下遍历
        if(!p){New(x,fa),pushup(fa),Splay(o);break;}//到达叶子节点位置,插入并将其拉到顶上去
    }
}
inline int ask_level(Re p,Re x){//查询数x的排名
//printf("p: %d\n",p);exit(0);
    if(x==pv){Re ans=tr[pl].size+1;Splay(p);return ans;}//找到了这个数
    else return x<pv?ask_level(pl,x):tr[p].cnt+tr[pl].size+ask_level(pr,x);
}
inline int ask_v(Re p,Re x){//查询排名为x的数
//    if(!p)return 0;//如果没找到这个数
    if(x<=tr[pl].size)return ask_v(pl,x);
    else{
        Re tmp=tr[pl].size+tr[p].cnt;
        return x<=tmp?pv:ask_v(pr,x-tmp);
    }
}
inline int ask_nex_p(Re p){p=pr;while(pl)p=pl;return p;}//从节点p开始查询猴急的位置
inline int ask_pri_p(Re p){p=pl;while(pr)p=pr;return p;}//从节点p开始查询前驱的位置
inline void del(Re x){
    ask_level(root,x);Re p=root;//找到这个点并拉成root
    if(tr[p].cnt>1){--tr[p].cnt,--tr[p].size;return;}//有副本
    if(!pl&&!pr){root=0;return;}//没有儿子
    if(!pl||!pr){tr[root=pl+pr].fa=0;return;}//只有一个儿子,直接将其儿子改为根
    Splay(ask_pri_p(root));//把它的前驱拉上去,然后它的右儿子就是原root(即x)
    tr[root].ps[1]=pr,tr[pr].fa=root;//删除原root(即x)
    pushup(root);
}
int main(){
    in(T);
    while(T--){
        in(a),in(b);
        if(a==1)insert(b);
        if(a==2)del(b);
        if(a==3)printf("%d\n",ask_level(root,b));
        if(a==4)printf("%d\n",ask_v(root,b));
        if(a==5)insert(b),printf("%d\n",tr[ask_pri_p(root)].v),del(b);
        if(a==6)insert(b),printf("%d\n",tr[ask_nex_p(root)].v),del(b);
    }
}

(2).【维护序列】

【模板】 数列 \(\text{[P2710]}\)

【模板】 维护数列 \(\text{[NOI2005] [P2042]}\)

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#define LL long long
#define Re register int
using namespace std;
const int N=2e5+3,inf=1e9;
int n,x,y,z,T,A[N];char op[20];
inline void in(Re &x){
    int f=0;x=0;char c=getchar();
    while(c<'0'||c>'9')f|=c=='-',c=getchar();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
    x=f?-x:x;
}
struct Splay{
    #define pl (tr[p].ps[0])
    #define pr (tr[p].ps[1])
    #define pf (tr[p].fa)
    #define pv (tr[p].v)
    int O,root,Q[N];queue<int>D;
    struct QAQ{int v,S,fa,max,lmax,rmax,size,ps[2];bool tag,turn;}tr[N];
    inline void pushup(Re p){
        tr[p].S=tr[pl].S+tr[pr].S+pv;
        tr[p].size=tr[pl].size+tr[pr].size+1;
        tr[p].lmax=max(tr[pl].lmax,tr[pl].S+pv+tr[pr].lmax);
        tr[p].rmax=max(tr[pr].rmax,tr[pr].S+pv+tr[pl].rmax);
        tr[p].max=max(tr[pl].rmax+pv+tr[pr].lmax,max(tr[pl].max,tr[pr].max));
    }
    inline void updata(Re p){tr[p].turn^=1,swap(pl,pr),swap(tr[p].lmax,tr[p].rmax);}
    inline void updata(Re p,Re v){
        tr[p].tag=1,tr[p].S=(pv=v)*tr[p].size;
        if(v>0)tr[p].lmax=tr[p].rmax=tr[p].max=tr[p].S;
        else tr[p].lmax=tr[p].rmax=0,tr[p].max=v;
    }
    inline void pushdown(Re p){
        if(tr[p].tag){
            if(pl)updata(pl,pv);
            if(pr)updata(pr,pv);
            tr[p].tag=tr[p].turn=0;
        }
        if(tr[p].turn){
            if(pl)updata(pl);
            if(pr)updata(pr);
            tr[p].turn=0;
        }
    }
    inline int which(Re p){return tr[pf].ps[1]==p;}
    inline void connect(Re p,Re fa,Re o){tr[pf=fa].ps[o]=p;}
    inline void rotate(Re p){
        Re fa=pf,fas=which(p);
        Re pa=tr[fa].fa,pas=which(fa);
        Re x=tr[p].ps[fas^1];
        connect(x,fa,fas),connect(fa,p,fas^1),connect(p,pa,pas);
        pushup(fa),pushup(p);
    }
    inline void splay(Re p,Re to){
        Re x=p,t=0;Q[++t]=x;
        while(tr[x].fa)Q[++t]=x=tr[x].fa;
        while(t)pushdown(Q[t--]);
        for(Re fa;pf!=to;rotate(p))
            if(tr[fa=pf].fa!=to)rotate(which(p)==which(fa)?fa:p);
        if(!to)root=p;
    }
    inline void CL(Re p){
        tr[p].size=tr[p].turn=tr[p].tag=tr[p].lmax=tr[p].rmax=tr[p].S=pv=pf=pl=pr=0,tr[p].max=-inf;
    }
    inline int New(){
        Re p;
        if(D.empty())p=++O;
        else p=D.front(),D.pop();
        CL(p),tr[p].size=1;return p;
    }
    inline void build(Re &p,Re L,Re R,Re fa){
        if(L>R)return;Re mid=(L+R)>>1;p=New(),pv=A[mid],pf=fa;
        build(pl,L,mid-1,p),build(pr,mid+1,R,p);
        pushup(p);
    }
    inline void recycle(Re p){
        if(pl)recycle(pl);
        if(pr)recycle(pr);
        D.push(p),CL(p);
    }
    inline int find(Re p,Re K){
        pushdown(p);
        if(K<=tr[pl].size)return find(pl,K);
        return K<=tr[pl].size+1?p:find(pr,K-tr[pl].size-1);
    }
    inline int split(Re L,Re R){
        Re p=find(root,L-1),q=find(root,R+1);
        splay(p,0),splay(q,p);return tr[q].ps[0];
    }
    inline void insert(Re st,Re m){
        for(Re i=1;i<=m;++i)in(A[i]);
        Re rt=0;build(rt,1,m,0);
        Re p=find(root,st),q=find(root,st+1);
        splay(p,0),splay(q,p);
        connect(rt,q,0),pushup(q),pushup(p);
    }
    inline void erase(Re L,Re R){
        Re p=split(L,R),fa=pf;
        tr[fa].ps[0]=pf=0,recycle(p);
        pushup(fa),pushup(tr[fa].fa);
    }
    inline int ask(Re L,Re R){return tr[split(L,R)].S;}
    inline int ask_max(Re L,Re R){return tr[split(L,R)].max;}
    inline void change(Re L,Re R,Re v){
        Re p=split(L,R);updata(p,v),pushup(pf),pushup(tr[pf].fa);
    }
    inline void reverse(Re L,Re R){
        Re p=split(L,R);
        if(!tr[p].tag)updata(p),pushup(pf),pushup(tr[pf].fa);
    }
}TR;
int main(){
    in(n),in(T),TR.tr[0].max=A[1]=A[n+2]=-inf;
    for(Re i=2;i<=n+1;++i)in(A[i]);
    TR.build(TR.root,1,n+2,0);
    while(T--){
        scanf("%s",op);
        if(op[0]=='M'&&op[2]=='X')in(x),in(y),++x,printf("%d\n",TR.ask_max(x,x+y-1));
        else if(op[0]=='G'&&(int)strlen(op)==3)in(x),++x,printf("%d\n",TR.ask(x,x));
        else{
            in(x),in(y),++x;
            if(op[0]=='I')TR.insert(x,y);
            if(op[0]=='D')TR.erase(x,x+y-1);
            if(op[0]=='M')in(z),TR.change(x,x+y-1,z);
            if(op[0]=='R')TR.reverse(x,x+y-1);
            if(op[0]=='G')printf("%d\n",TR.ask(x,x+y-1));
        }
    }
}

4.【AVL】

5.【SBT】

6.【红黑树】

7.【替罪羊树】


九:【珂朵莉树】

【模板】 \(\text{Willem, Chtholly and Seniorious}\) \(\text{CF896C}\)

#include<algorithm>
#include<cstdio>
#include<vector>
#include<set>
#define LL long long
#define Re register int
#define IT set<QAQ>::iterator
using namespace std;
const int N=1e5+5;
struct QAQ{
    int l,r;mutable LL v;
    QAQ(int L,int R=-1,LL V=0):l(L),r(R),v(V){}
    bool operator<(QAQ o)const{return l<o.l;}
};
int l,r,x,y,n,m,fu,op,seed,vmax,a[N];set<QAQ>s;
inline int rnd(){
    Re tmp=seed;
    seed=((LL)seed*7+13)%1000000007;
    return tmp;
}
inline LL mi(LL a,LL k,LL P){
    LL ans=1;a%=P;
    while(k){
        if(k&1)(ans*=a)%=P;
        (a*=a)%=P,k>>=1;
    }
    return ans;
}
inline IT split(Re w){//分裂
    IT it=s.lower_bound(QAQ(w));
    if(it!=s.end()&&it->l==w)return it;
    --it;
    Re L=it->l,R=it->r;LL V=it->v;
    s.erase(it);s.insert(QAQ(L,w-1,V));
    return s.insert(QAQ(w,R,V)).first;
}
inline void assign(Re l,Re r,LL v){//区间推平
    IT itr=split(r+1),itl=split(l);
    s.erase(itl,itr),s.insert(QAQ(l,r,v));
}
inline void add(Re l,Re r,LL v){//区间加
    IT itr=split(r+1),itl=split(l);
    while(itl!=itr)itl->v+=v,++itl;
}
inline LL mi_sum(Re l,Re r,Re k,Re P){//区间幂次和
    IT itr=split(r+1),itl=split(l);LL ans=0;
    while(itl!=itr)(ans+=(LL)(itl->r-itl->l+1)%P*mi(itl->v,(LL)k,(LL)P)%P)%=P,++itl;
    return ans;
}
inline LL ask_k(Re l,Re r,Re k){//区间第k大
    IT itr=split(r+1),itl=split(l);
    vector<pair<LL,int> >Q;
    Q.clear();
    while(itl!=itr)Q.push_back(pair<LL,int>(itl->v,itl->r-itl->l+1)),++itl;
    sort(Q.begin(),Q.end());
    for(vector<pair<LL,int> >::iterator it=Q.begin();it!=Q.end();++it){
        k-=it->second;
        if(k<=0)return it->first;
    }
}
int main(){
    scanf("%d%d%d%d",&n,&m,&seed,&vmax);
    for(Re i=1;i<=n;++i)a[i]=(rnd()%vmax)+1,s.insert(QAQ(i,i,a[i]));
    s.insert(QAQ(n+1,n+1,0));
    while(m--){
        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;
        
        if(op<2)add(l,r,(LL)x);
        else if(op<3)assign(l,r,(LL)x);
        else if(op<4)printf("%lld\n",ask_k(l,r,x));
        else printf("%lld\n",mi_sum(l,r,x,y));
    }
}

十:【喵树】

喵喵喵?

posted @ 2019-10-27 21:30  辰星凌  阅读(693)  评论(1编辑  收藏  举报