P1486 [NOI2004]郁闷的出纳员
作者:互联网
这道题需要动态插入,删除,求排名,看到这就想到了平衡树。由于本人只会splay,所以就用splay来做这道题,这道题插入和删除都是模板,但是题中还有一个比价坑的地方就是工资的调整。但我做不到在平衡树上修改点权。如果每一个都去插入和删除的复杂度显然非常高。看了题解发现,可以维护一个变量来记录每次工资调整时的值delta,像这样的话我们插入的k值就应该是k-delta,为什么要这样做呢,因为我们显然无法修改之前的点权,这样一来就是维护一个相对的大小。
重点还有如何把工资低于下界的人都删去。我们在操作之前提前插入两个哨兵节点+/-inf,这样可以避免操作时的错误,这是一个技巧,需要记住。在删除的时候把权值为-inf的点旋转到根节点,然后将全值为下界的点转到根节点的右儿子上,这是根节点右儿子的左儿子就是比工资下界小的所有节点,然后直接删除即可。
注意再求排名的时候要减去两个插入的哨兵节点。
代码如下:
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+7; const int inf=0x7fffffff; int n,minn; char opt[maxn]; int key[maxn],fa[maxn],cnt[maxn],size[maxn],ch[maxn][2]; int rt,sz; int k; int tot; int delta; void pushup(int x){ size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x]; } bool check(int x){ return ch[fa[x]][1]==x; } void clear(int x){ fa[x]=cnt[x]=size[x]=ch[x][1]=ch[x][0]=key[x]=0; } void rotate(int x){ int y=fa[x],z=fa[y],who=check(x); ch[y][who]=ch[x][who^1]; fa[ch[y][who]]=y; ch[x][who^1]=y; fa[y]=x,fa[x]=z; if(z) ch[z][ch[z][1]==y]=x; pushup(y);pushup(x); } void splay(int x,int goal){ for(int f;(f=fa[x])!=goal;rotate(x)){ if(fa[f]!=goal) rotate((check(f)==check(x))?f:x); } if(!goal) rt=x; } void insert(int x){ if(!rt){ rt=++sz; key[sz]=x; size[sz]=1; cnt[sz]=1; return; } int now=rt,f=0; while(1){ if(key[now]==x){ cnt[now]++; pushup(f); pushup(now); splay(now,0); return; } f=now,now=ch[now][key[now]<x]; if(!now){ sz++; size[sz]=cnt[sz]=1; fa[sz]=f; ch[f][key[f]<x]=sz; key[sz]=x; pushup(f); splay(sz,0); return; } } } int nxt(){ int now=ch[rt][1]; while(ch[now][0]) now=ch[now][0]; return now; } int pre(){ int now=ch[rt][0]; while(ch[now][1]) now=ch[now][1]; return now; } int id(int x){ int now=rt; while(1){ if(x==key[now]) return now; else{ if(x<key[now]) now=ch[now][0]; else now=ch[now][1]; } } } int rank(int x){ int now=rt,ans=0; while(1){ if(x<key[now]) now=ch[now][0]; else{ ans+=size[ch[now][0]]; if(x==key[now]){ splay(now,0); return ans+1; } ans+=cnt[now]; now=ch[now][1]; } } } void del(int x){ rank(x); if(cnt[rt]>1){ cnt[rt]--; pushup(rt); return; } if(!ch[rt][1]&&!ch[rt][0]){ clear(rt); rt=0; return; } if(!ch[rt][1]){ int oldroot=rt; rt=ch[rt][0]; fa[rt]=0; clear(oldroot); return; } else if(!ch[rt][0]){ int oldroot=rt; rt=ch[rt][1]; fa[rt]=0; clear(oldroot); return; } int oldroot=rt,left=pre(); splay(left,0); fa[ch[oldroot][1]]=rt; ch[rt][1]=ch[oldroot][1]; clear(oldroot); pushup(rt); } int val(int x){ int now=rt; while(1){ if(ch[now][0]&&x<=size[ch[now][0]]) now=ch[now][0]; else{ int tmp=size[ch[now][0]]+cnt[now]; if(x<=tmp) return key[now]; x-=tmp; now=ch[now][1]; } } } int main(){ scanf("%d%d",&n,&minn); insert(inf); insert(-inf); for(int i=1;i<=n;i++){ scanf("%s",opt); if(opt[0]=='I'){ scanf("%d",&k); if(k<minn) continue; insert(k-delta); tot++; } if(opt[0]=='A'){ scanf("%d",&k); delta+=k; } if(opt[0]=='S'){ scanf("%d",&k); delta-=k; insert(minn-delta); int a=id(minn-delta); int b=id(-inf); splay(b,0); splay(a,b); ch[ch[rt][1]][0]=0; del(minn-delta); } if(opt[0]=='F'){ scanf("%d",&k); int kkksc03=rank(inf)-2; if(kkksc03<k){ printf("-1\n"); continue; } int ans=val(kkksc03+2-k); printf("%d\n",ans+delta); } } int kkksc03=rank(inf)-2; int ans=tot-kkksc03; printf("%d\n",ans); return 0; }View Code
标签:rt,ch,P1486,int,出纳员,oldroot,fa,NOI2004,now 来源: https://www.cnblogs.com/LJB666/p/11559826.html