bzoj3196 Tyvj 1730 二逼平衡树(树套树,线段树套splay/bit套动态开点线段树)

线段树套splay,看网上题解大部分说套splay是过不去的,需要优越的姿势才可以,本想着过不去再卡一卡优越的姿势的,然而过了qaq。
线段树维护区间,对于线段树的每个节点我们吊一棵splay维护区间内的权值。
操作1:查询k在区间[l,r]上的排名。
线段树上查询区间,去splay上查询小于k的有多少个,都加起来即可,再加1就是k的排名。
操作2:查询区间[l,r]上的排名为k的数。
这个操作比较精妙,我们先二分答案,然后去查mid的排名,调整答案即可。
操作3:修改x的权值为val。
相当于线段树单点修改,把原来的删了,再ins新的进去即可。
操作4:查询区间[l,r]上的k的前驱。
线段树上查询区间,去splay上查前驱,取max即可。
操作5:查询区间[l,r]上的k的后继。
线段树上查询区间,去splay上查后继,取min即可。
空间复杂度 O((n+m)logn) O ( ( n + m ) l o g n ) 或者 O(nlogn) O ( n l o g n )
操作2是 O(logwlog2n)O(log2n) O ( l o g w l o g 2 n ) 的 吧 , 其 它 操 作 都 是 O ( l o g 2 n )
时间复杂度 O(mlog2nlogw) O ( m l o g 2 n l o g w )
不过为什么大家都说是 O(nlog2n) O ( n l o g 2 n ) 的呢(迷
tips:要注意重复权值的处理哟,和普通平衡树一样的处理就好了

2.26upd: 树状数组套动态开点线段树
本以为空间怎么算都是过不去的,然而大家都说离散化权值以后,最多8e6的就够了。蒟蒻算了算树状数组所需的节点个数,好像确实比nlogn要少一半左右。动态开点线段树新建一条链均摊下来应该也要比logn小一些。但是具体能卡到多少并不是很会。
能开的下的话就很好做了,常数也很小。类似bzoj1901

2.28upd:写了一下线段树套treap,确实比splay快一些。

线段树套splay

#include 
#include 
#include 
#include 
using namespace std;
#define ll long long
#define inf 2147483647
#define N 50010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,a[N],rt[N<<2],fa[N*40],c[N*40][2],v[N*40],sz[N*40],cnt[N*40],owo=0;
int pos[N],mx=0,ans;
inline void update(int x){
    int l=c[x][0],r=c[x][1];
    sz[x]=sz[l]+sz[r]+cnt[x];
}
inline void rotate(int x,int &k){
    int y=fa[x],z=fa[y],l=x==c[y][1],r=l^1;
    if(y==k) k=x;
    else c[z][y==c[z][1]]=x;
    fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
    c[y][l]=c[x][r];c[x][r]=y;update(y);update(x);
}
inline void splay(int x,int &k){
    while(x!=k){
        int y=fa[x],z=fa[y];
        if(y!=k){
            if(x==c[y][1]^y==c[z][1]) rotate(x,k);
            else rotate(y,k);
        }rotate(x,k);
    }
}
inline int find(int p,int x){
    if(v[p]==x) return p;
    if(xreturn find(c[p][0],x);
    return find(c[p][1],x);
}
inline void ins(int &p,int x,int Fa,int id){
    if(!p){
        p=++owo;fa[p]=Fa;c[p][0]=c[p][1]=0;v[p]=x;sz[p]=cnt[p]=1;splay(p,rt[id]);return;
    }if(v[p]==x){cnt[p]++;sz[p]++;splay(p,rt[id]);return;}
    if(x0],x,p,id);
    else ins(c[p][1],x,p,id);
}
inline int qrank(int p,int x){//查询比x小的数有几个
    if(!p) return 0;
    if(xreturn qrank(c[p][0],x);
    if(x==v[p]) return sz[c[p][0]];
    return sz[c[p][0]]+cnt[p]+qrank(c[p][1],x);
}
inline void del(int id,int val){
    int x=find(rt[id],val);splay(x,rt[id]);
    if(cnt[x]>1){cnt[x]--;sz[x]--;return;}
    if(c[x][0]*c[x][1]==0){
        rt[id]=c[x][0]+c[x][1];fa[rt[id]]=c[x][0]=c[x][1]=0;return;
    }int pre=c[x][0],succ=c[x][1];
    while(c[pre][1]) pre=c[pre][1];while(c[succ][0]) succ=c[succ][0];
    splay(pre,rt[id]);splay(succ,c[pre][1]);c[succ][0]=fa[x]=0;
    update(succ);update(pre);
}
inline int getpre(int rt,int x){
    int res=-inf,p=rt;
    while(p){
        if(v[p]1];
        else p=c[p][0];
    }return res;
}
inline int getsucc(int rt,int x){
    int res=inf,p=rt;
    while(p){
        if(v[p]>x) res=v[p],p=c[p][0];
        else p=c[p][1];
    }return res;
}
inline void seg_ins(int p,int l,int r,int x,int val){
    ins(rt[p],val,0,p);
    if(l==r) return;int mid=l+r>>1;
    if(x<=mid) seg_ins(p<<1,l,mid,x,val);
    else seg_ins(p<<1|1,mid+1,r,x,val);
}
inline int seg_rank(int p,int l,int r,int x,int y,int val){
    if(x<=l&&r<=y) return qrank(rt[p],val);
    int mid=l+r>>1,res=0;
    if(x<=mid) res+=seg_rank(p<<1,l,mid,x,y,val);
    if(y>mid) res+=seg_rank(p<<1|1,mid+1,r,x,y,val);
    return res;
}
inline void seg_change(int p,int l,int r,int x,int val){
    del(p,a[x]);ins(rt[p],val,0,p);
    if(l==r) return;int mid=l+r>>1;
    if(x<=mid) seg_change(p<<1,l,mid,x,val);
    else seg_change(p<<1|1,mid+1,r,x,val);
}
inline int getkth(int x,int y,int k){
    int l=0,r=mx;
    while(l<=r){
        int mid=l+r>>1;
        if(seg_rank(1,1,n,x,y,mid)1;
        else r=mid-1;
    }return l-1;
}
inline void seg_pre(int p,int l,int r,int x,int y,int val){
    if(x<=l&&r<=y){ans=max(ans,getpre(rt[p],val));return;}
    int mid=l+r>>1;
    if(x<=mid) seg_pre(p<<1,l,mid,x,y,val);
    if(y>mid) seg_pre(p<<1|1,mid+1,r,x,y,val);
}
inline void seg_succ(int p,int l,int r,int x,int y,int val){
    if(x<=l&&r<=y){ans=min(ans,getsucc(rt[p],val));return;}
    int mid=l+r>>1;
    if(x<=mid) seg_succ(p<<1,l,mid,x,y,val);
    if(y>mid) seg_succ(p<<1|1,mid+1,r,x,y,val);
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;++i) a[i]=read(),seg_ins(1,1,n,i,a[i]),mx=max(mx,a[i]);
    while(m--){
        int op=read();
        if(op==3){int x=read(),val=read();seg_change(1,1,n,x,val);a[x]=val;mx=max(mx,val);continue;}
        int l=read(),r=read(),k=read();
        if(op==1) printf("%d\n",seg_rank(1,1,n,l,r,k)+1);
        if(op==2) printf("%d\n",getkth(l,r,k));
        if(op==4){ans=-inf;seg_pre(1,1,n,l,r,k);printf("%d\n",ans);}
        if(op==5){ans=inf;seg_succ(1,1,n,l,r,k);printf("%d\n",ans);}
    }return 0;
}

树状数组套动态开点线段树

#include 
#include 
#include 
#include 
using namespace std;
#define ll long long
#define inf 2147483647
#define N 50010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,aa[N<<1],a[N],rt[N],num=0,owo=0,p1[N],p2[N],n1,n2;
struct node{
    int lc,rc,sum;
}tr[N*80*2];
struct oper{
    int op,l,r,k;
}e[N];
inline void add(int &p,int l,int r,int x,int val){
    if(!p) p=++owo;tr[p].sum+=val;
    if(l==r) return;int mid=l+r>>1;
    if(x<=mid) add(tr[p].lc,l,mid,x,val);
    else add(tr[p].rc,mid+1,r,x,val);
}
inline void bit_add(int x,int pos,int val){
    for(;x<=n;x+=x&-x) add(rt[x],1,num,pos,val);
}
inline void gao1(int x){
    n1=0;for(;x;x-=x&-x) p1[++n1]=rt[x];
}
inline void gao2(int x){
    n2=0;for(;x;x-=x&-x) p2[++n2]=rt[x];
}
inline int qless(int l,int r,int x){
    if(l==r) return 0; 
    int mid=l+r>>1,res=0;
    if(x<=mid){
        for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].lc;
        for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].lc;
        return qless(l,mid,x);
    }else{
        for(int i=1;i<=n1;++i) res+=tr[tr[p1[i]].lc].sum;
        for(int i=1;i<=n2;++i) res-=tr[tr[p2[i]].lc].sum;
        for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].rc;
        for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].rc;
        return res+qless(mid+1,r,x);
    }
}
inline int qmore(int l,int r,int x){
    if(l==r) return 0;
    int mid=l+r>>1,res=0;
    if(x1){
        for(int i=1;i<=n1;++i) res+=tr[tr[p1[i]].rc].sum;
        for(int i=1;i<=n2;++i) res-=tr[tr[p2[i]].rc].sum;       
        for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].lc;
        for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].lc;
        return res+qmore(l,mid,x);
    }else{
        for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].rc;
        for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].rc;
        return qmore(mid+1,r,x);
    }
}
inline int qkth(int l,int r,int k){
    if(l==r) return l;
    int res=0,mid=l+r>>1;
    for(int i=1;i<=n1;++i) res+=tr[tr[p1[i]].lc].sum;
    for(int i=1;i<=n2;++i) res-=tr[tr[p2[i]].lc].sum;
    if(k<=res){
        for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].lc;
        for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].lc;
        return qkth(l,mid,k);
    }
    for(int i=1;i<=n1;++i) p1[i]=tr[p1[i]].rc;
    for(int i=1;i<=n2;++i) p2[i]=tr[p2[i]].rc;
    return qkth(mid+1,r,k-res);
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();num=n;
    for(int i=1;i<=n;++i) aa[i]=a[i]=read();
    for(int i=1;i<=m;++i){
        e[i].op=read();e[i].l=read();e[i].r=read();
        if(e[i].op==3){aa[++num]=e[i].r;continue;}
        e[i].k=read();if(e[i].op!=2) aa[++num]=e[i].k;
    }sort(aa+1,aa+num+1);num=unique(aa+1,aa+num+1)-aa-1;
    for(int i=1;i<=n;++i) a[i]=lower_bound(aa+1,aa+num+1,a[i])-aa,bit_add(i,a[i],1);
    for(int i=1;i<=m;++i){
        if(e[i].op==1){
            e[i].k=lower_bound(aa+1,aa+num+1,e[i].k)-aa;
            gao1(e[i].r);gao2(e[i].l-1);
            printf("%d\n",qless(1,num,e[i].k)+1);continue;
        }if(e[i].op==2){
            gao1(e[i].r);gao2(e[i].l-1);
            printf("%d\n",aa[qkth(1,num,e[i].k)]);continue;
        }if(e[i].op==3){
            e[i].r=lower_bound(aa+1,aa+num+1,e[i].r)-aa;
            int x=e[i].l;bit_add(x,a[x],-1);
            a[x]=e[i].r;bit_add(x,a[x],1);continue;
        }if(e[i].op==4){
            e[i].k=lower_bound(aa+1,aa+num+1,e[i].k)-aa;
            gao1(e[i].r);gao2(e[i].l-1);
            int pos=qless(1,num,e[i].k);
            if(!pos){printf("%d\n",-inf);continue;}
            gao1(e[i].r);gao2(e[i].l-1);
            printf("%d\n",aa[qkth(1,num,pos)]);continue;
        }if(e[i].op==5){
            e[i].k=lower_bound(aa+1,aa+num+1,e[i].k)-aa;
            gao1(e[i].r);gao2(e[i].l-1);
            int pos=qmore(1,num,e[i].k),sz=e[i].r-e[i].l+1;
            if(!pos){printf("%d\n",inf);continue;}
            gao1(e[i].r);gao2(e[i].l-1);
            printf("%d\n",aa[qkth(1,num,sz-pos+1)]);continue;
        }
    }return 0;
}

线段树套treap

#include 
#include 
#include 
#include 
using namespace std;
#define ll long long
#define inf 2147483647
#define N 50010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,m,a[N],rt[N<<2],ls[N*40],rs[N*40],v[N*40],sz[N*40],cnt[N*40],rnd[N*40],owo=0;
int pos[N],mx=0,ans;
inline void update(int p){sz[p]=sz[ls[p]]+sz[rs[p]]+cnt[p];}
inline void rturn(int &y){int x=ls[y];ls[y]=rs[x];rs[x]=y;update(y);update(x);y=x;}
inline void lturn(int &y){int x=rs[y];rs[y]=ls[x];ls[x]=y;update(y);update(x);y=x;}
inline void ins(int &p,int x){
    if(!p){p=++owo;v[p]=x;sz[p]=cnt[p]=1;rnd[p]=rand();return;}
    if(v[p]==x){cnt[p]++;sz[p]++;return;}++sz[p];
    if(xif(rnd[ls[p]]else {ins(rs[p],x);if(rnd[rs[p]]inline int qrank(int p,int x){//查询比x小的数有几个
    if(!p) return 0;
    if(xreturn qrank(ls[p],x);
    if(x==v[p]) return sz[ls[p]];
    return sz[ls[p]]+cnt[p]+qrank(rs[p],x);
}
inline void del(int &p,int x){
    if(v[p]==x){
        if(cnt[p]>1) cnt[p]--,sz[p]--;
        else if(ls[p]*rs[p]==0) p=ls[p]+rs[p];
        else if(rnd[ls[p]]else lturn(p),del(p,x);return;
    }sz[p]--;
    if(xelse del(rs[p],x);
}
inline int getpre(int rt,int x){
    int res=-inf,p=rt;
    while(p){
        if(v[p]else p=ls[p];
    }return res;
}
inline int getsucc(int rt,int x){
    int res=inf,p=rt;
    while(p){
        if(v[p]>x) res=v[p],p=ls[p];
        else p=rs[p];
    }return res;
}
inline void seg_ins(int p,int l,int r,int x,int val){
    ins(rt[p],val);
    if(l==r) return;int mid=l+r>>1;
    if(x<=mid) seg_ins(p<<1,l,mid,x,val);
    else seg_ins(p<<1|1,mid+1,r,x,val);
}
inline int seg_rank(int p,int l,int r,int x,int y,int val){
    if(x<=l&&r<=y) return qrank(rt[p],val);
    int mid=l+r>>1,res=0;
    if(x<=mid) res+=seg_rank(p<<1,l,mid,x,y,val);
    if(y>mid) res+=seg_rank(p<<1|1,mid+1,r,x,y,val);
    return res;
}
inline void seg_change(int p,int l,int r,int x,int val){
    del(rt[p],a[x]);ins(rt[p],val);
    if(l==r) return;int mid=l+r>>1;
    if(x<=mid) seg_change(p<<1,l,mid,x,val);
    else seg_change(p<<1|1,mid+1,r,x,val);
}
inline int getkth(int x,int y,int k){
    int l=0,r=mx;
    while(l<=r){
        int mid=l+r>>1;
        if(seg_rank(1,1,n,x,y,mid)1;
        else r=mid-1;
    }return l-1;
}
inline void seg_pre(int p,int l,int r,int x,int y,int val){
    if(x<=l&&r<=y){ans=max(ans,getpre(rt[p],val));return;}
    int mid=l+r>>1;
    if(x<=mid) seg_pre(p<<1,l,mid,x,y,val);
    if(y>mid) seg_pre(p<<1|1,mid+1,r,x,y,val);
}
inline void seg_succ(int p,int l,int r,int x,int y,int val){
    if(x<=l&&r<=y){ans=min(ans,getsucc(rt[p],val));return;}
    int mid=l+r>>1;
    if(x<=mid) seg_succ(p<<1,l,mid,x,y,val);
    if(y>mid) seg_succ(p<<1|1,mid+1,r,x,y,val);
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();m=read();srand(20000712);
    for(int i=1;i<=n;++i) a[i]=read(),seg_ins(1,1,n,i,a[i]),mx=max(mx,a[i]);
    while(m--){
        int op=read();
        if(op==3){int x=read(),val=read();seg_change(1,1,n,x,val);a[x]=val;mx=max(mx,val);continue;}
        int l=read(),r=read(),k=read();
        if(op==1) printf("%d\n",seg_rank(1,1,n,l,r,k)+1);
        if(op==2) printf("%d\n",getkth(l,r,k));
        if(op==4){ans=-inf;seg_pre(1,1,n,l,r,k);printf("%d\n",ans);}
        if(op==5){ans=inf;seg_succ(1,1,n,l,r,k);printf("%d\n",ans);}
    }return 0;
}

你可能感兴趣的:(bzoj,树状数组,线段树,主席树,平衡树,树套树)