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 线段树套平衡树的主要内容,如果未能解决你的问题,请参考以下文章