P3380 线段树套平衡树

Posted Sherlockk

tags:

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

(智商不够用,只能写一点大码数据结构裸题来骗题量)

最近数据结构的题基本都能1A了,很开心O(∩_∩)O~~

丢一个模板以供日后参考

每棵线段树节点上挂一个平衡树,每个位置最多在logn个平衡树上,空间就是nlogn的

再写一个空间回收(灰常好写)就保证了操作过多不会影响空间

一些细节:平衡树后仍需离散化来减小二分上限;

在不确定树上是否有 x 时,平衡树的 rank 函数要稍作改动

关于操作 2 的二分,如果区间内有重复的数,要注意询问的排名与查询的排名可能的差别

注意 splay 或删除后及时换根,因此多用 &引用 传入参数会方便很多

线段树存储的东西越来越少了(只剩一个平衡树的根了),好像变成了一种虚拟的模型了。。

//P3380
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define uLL unsigned long long
#define rint register int
#define itn int
#define mem(x) memset(x,0,sizeof(x))
#define debug puts("!!!");
inline LL read(){
   LL x=0,ff=1;char ss=getchar();
   while(ss<\'0\'||ss>\'9\'){if(ss==\'-\')ff=-1;ss=getchar();}
   while(ss<=\'9\'&&ss>=\'0\'){x=x*10+ss-\'0\';ss=getchar();}
   return ff*x;
}
inline void writee(LL x){
   if(x<0){putchar(\'-\');x=-x;}
   if(x>9)writee(x/10);
   putchar(x%10+\'0\');
}
inline void write(LL x){writee(x);putchar(\'\\n\');}
inline int min(int x,int y){return x<y?x:y;}
inline int max(int x,int y){return x>y?x:y;}



const int N=5e4+10,M=N*40;
const LL inf=1e14,mod=998244353;
int n,m,q;
int a[N],b[N<<1],b1[N<<1];
struct node{
    int op,l,r,k;
}query[N];
int rt[N<<2],siz[M],ch[M][2],val[M],fa[M],cnt[M],totnode=1;
int dsta[M],dtop;
void update(int p){siz[p]=siz[ch[p][1]]+siz[ch[p][0]]+cnt[p];}
void del(int p){fa[p]=ch[p][0]=ch[p][1]=siz[p]=val[p]=cnt[p]=0;dsta[++dtop]=p;}
int newnode(int f,int v){
    int p=dtop?dsta[dtop--]:++totnode;
    fa[p]=f;ch[p][0]=ch[p][1]=0;siz[p]=cnt[p]=1;
    val[p]=v;return p;
}
void rot(int p){
    int f=fa[p];bool d=(ch[f][1]==p);
    fa[p]=fa[f];if(fa[f])ch[fa[f]][ch[fa[f]][1]==f]=p;
    fa[f]=p;ch[f][d]=ch[p][!d];if(ch[p][!d])fa[ch[p][!d]]=f;
    ch[p][!d]=f;update(f);
}
void splay(int p,int goal){
    while(fa[p]!=goal){
        int f=fa[p],ff=fa[f];
        if(ff!=goal)rot((ch[ff][1]==f)==(ch[f][1]==p)?f:p);
        rot(p);
    }update(p);
}
void insert(int &root,int v){
    int f=0,now=root;
    while(val[now]!=v&&now){f=now;now=ch[f][v>val[f]];}
    if(now)cnt[now]++;
    else{
        now=newnode(f,v);
        if(f)ch[f][v>val[f]]=now;
    }
    splay(now,0);root=now;
}
int rank(int p,int v){
    if(v==val[p])return siz[ch[p][0]];
    if(v<val[p])return ch[p][0]?rank(ch[p][0],v):0;
    else return ch[p][1]?rank(ch[p][1],v)+siz[ch[p][0]]+cnt[p]:siz[p];
}

int nxt(int &root,int x){
    int now=root,ans=-1;
    while(now){
        if(val[now]>x){
            if(ans==-1||val[ans]>val[now])ans=now;
            now=ch[now][0];    
        }
        else now=ch[now][1];
    }
    if(ans==-1)return -1;
    splay(ans,0);root=ans;
    return val[ans];
}
int lst(int &root,int x){
    int now=root,ans=-1;
    while(now){
        if(val[now]<x){
            if(ans==-1||val[ans]<val[now])ans=now;
            now=ch[now][1];    
        }
        else now=ch[now][0];
    }
    if(ans==-1)return -1;
    splay(ans,0);root=ans;
    return val[ans];
}
itn kth(int p,int k){
    if(siz[ch[p][0]]>=k)return kth(ch[p][0],k);
    if(siz[ch[p][0]]+cnt[p]>=k)return val[p];
    else return kth(ch[p][1],k-siz[ch[p][0]]-cnt[p]);
}
int find(int &root,int x){
    int now=root;
    while(val[now]!=x)now=ch[now][x>val[now]];
    splay(now,0);root=now;return now;
}
void remove(int &root,int x){
    int p=find(root,x);
    if(cnt[p]>1){cnt[p]--;siz[p]--;return;}
    if(!ch[p][0]&&!ch[p][1]){del(p);root=0;return;}
    if(!ch[p][0]){
        root=ch[p][1];fa[ch[p][1]]=0;del(p);return;
    }if(!ch[p][1]){
        root=ch[p][0];fa[ch[p][0]]=0;del(p);return;
    }nxt(root,x);
    int lch=ch[p][0];del(p);fa[lch]=root;ch[root][0]=lch;
    update(root);
}
void dfsbug(itn p){
    cout<<val[p]<<\' \'<<cnt[p]<<endl;
    if(ch[p][0])dfsbug(ch[p][0]);
    if(ch[p][1])dfsbug(ch[p][1]);
}
void build(int p,int l,int r){
    for(rint i=l;i<=r;i++)insert(rt[p],a[i]);
    //cout<<p<<": ";
    //for(rint i=l;i<=r;i++)cout<<a[i]<<\' \';cout<<endl;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(p<<1,l,mid);build(p<<1|1,mid+1,r);
}


int segrank(int p,int l,int r,int s,int t,int x){
    if(s<=l&&r<=t){return rank(rt[p],x);}
    int mid=(l+r)>>1,val=0;
    if(s<=mid)val+=segrank(p<<1,l,mid,s,t,x);
    if(t>mid)val+=segrank(p<<1|1,mid+1,r,s,t,x);
    return val;
}
void segchange(int p,int l,int r,int pos,int x){
    remove(rt[p],a[pos]);insert(rt[p],x);
    if(l==r)return;
    int mid=(l+r)>>1;
    if(pos<=mid)segchange(p<<1,l,mid,pos,x);
    else segchange(p<<1|1,mid+1,r,pos,x);
}
int len,w[N];
void segpre(int p,int l,int r,int s,int t,int x){
    if(s<=l&&r<=t){int k=lst(rt[p],x);if(k!=-1)w[++len]=k;return;}
    int mid=(l+r)>>1;
    if(s<=mid)segpre(p<<1,l,mid,s,t,x);
    if(t>mid)segpre(p<<1|1,mid+1,r,s,t,x);
}
void segnxt(int p,int l,int r,int s,int t,int x){
    if(s<=l&&r<=t){int k=nxt(rt[p],x);if(k!=-1)w[++len]=k;return;}
    int mid=(l+r)>>1;
    if(s<=mid)segnxt(p<<1,l,mid,s,t,x);
    if(t>mid)segnxt(p<<1|1,mid+1,r,s,t,x);
}

int main(){
    //freopen("read.txt","r",stdin);
    n=read();q=read();
    for(rint i=1;i<=n;i++)a[i]=b[++m]=read();
    for(rint i=1;i<=q;i++){
        query[i].op=read();
        query[i].l=read();
        if(query[i].op!=3)query[i].r=read();
        b[++m]=query[i].k=read();
    }sort(b+1,b+1+m);
    int m1=0;b1[++m1]=b[1];
    for(rint i=2;i<=m;i++)if(b[i]!=b1[m1])b1[++m1]=b[i];
    m=m1;for(rint i=1;i<=n;i++)a[i]=lower_bound(b1+1,b1+1+m,a[i])-b1;
    for(rint i=1;i<=q;i++)
        if(query[i].op!=2)query[i].k=lower_bound(b1+1,b1+1+m,query[i].k)-b1;
    build(1,1,n);
    for(rint i=1;i<=q;i++){
        int o=query[i].op,ql=query[i].l,qr=query[i].r,qk=query[i].k;
        if(o==1)write(segrank(1,1,n,ql,qr,qk)+1);
        if(o==2){
            int l=1,r=m,ans=0;
            while(l<=r){
                int mid=(l+r)>>1;
                if(segrank(1,1,n,ql,qr,mid)+1>qk){r=mid-1;}
                else {ans=mid;l=mid+1;}
                //cout<<mid<<\' \'<<segrank(1,1,n,ql,qr,mid)<<\'!\'<<endl;
            }//cout<<ans<<\' \';
            write(b1[ans]);
        }
        if(o==3){segchange(1,1,n,ql,qk);a[ql]=qk;}
        if(o==4){
            len=0;segpre(1,1,n,ql,qr,qk);
            if(!len)puts("-2147483647");
            else{
                int ans=0;
                for(rint i=1;i<=len;i++)if(w[i]>ans)ans=w[i];
                write(b1[ans]);
            }
        }if(o==5){
            len=0;segnxt(1,1,n,ql,qr,qk);
            if(!len)puts("2147483647");
            else{
                int ans=1e9;
                for(rint i=1;i<=len;i++)if(w[i]<ans)ans=w[i];
                write(b1[ans]);
            }
        }
    }
}

 

以上是关于P3380 线段树套平衡树的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P3380 模板二逼平衡树(树套树,树状数组,线段树)

洛谷 P3380 模板二逼平衡树(树套树)

权值线段树套序列线段树

树套树-线段树套平衡树

[bzoj3065] 带插入区间第k小值 [重量平衡树套线段树]

bzoj3196 二逼平衡树——线段树套平衡树