非常垃圾的一道平衡树,结果被日了一天。很难受嗷嗷嗷
首先不得不说网上的题解让我这个本来就不熟悉平衡树的彩笔很难受——并不好理解。
还好Sinogi大佬非常的神,一眼就切掉了,而且用更加美妙的解法。
题意在操作时,就是第i次把编号为i-1和编号i的后继分别提到根和根的右儿子,根的右儿子的左子树打上翻转标记。
用外部数组记录原来高度第几大的在平衡树中编号是多少。就可以直接操作了。
注意有相同的高度,离散化时直接按高度第一关键字,编号第二关键字就行了。
还有每次splay要把根到当前节点都pushdown一遍。还有先pushdown再继续操作!包括判断有没有左右儿子!
可能只有我是傻逼吧
#include<bits/stdc++.h> using namespace std; const int N=200010; inline int read(){ int r=0,c=getchar(); while(!isdigit(c))c=getchar(); while(isdigit(c)) r=r*10+c-‘0‘,c=getchar(); return r; } #define ls ch[x][0] #define rs ch[x][1] int ch[N][2],siz[N],fa[N],rev[N],pos[N]; int rt,tot; struct qwq{ int v,p; }a[N]; bool cmpv(qwq p,qwq q){ if(p.v==q.v)return p.p<q.p; return p.v<q.v; } bool cmpp(qwq p,qwq q){ return p.p<q.p; } void pp(int x){ siz[x]=siz[ls]+siz[rs]+1; } void pd(int x){ if(rev[x]){ rev[x]=0; swap(ls,rs); rev[ls]^=1;rev[rs]^=1; } } int get(int x){ return x==ch[fa[x]][1]; } void rotate(int x){ int y=fa[x],z=fa[y],px=get(x),py=get(y); int t=ch[x][px^1]; ch[x][px^1]=y;fa[y]=x; ch[y][px]=t;fa[t]=y; if(z)ch[z][py]=x;fa[x]=z; pp(y); } int s[N]; void splay(int x,int lim){ int top=0; for(int i=x;i;i=fa[i])s[++top]=i; for(int i=top;i;i--)pd(s[i]); int y=fa[x]; while(y^lim){ if(fa[y]^lim) rotate(get(x)==get(y)?y:x); rotate(x);y=fa[x]; } rt=!lim?x:rt;pp(x); } int nxt(){ pd(rt);int x=ch[rt][1]; while(pd(x),ch[x][0])x=ch[x][0]; return x; } int build(int l,int r){ if(l>r)return 0; int mid=l+r>>1,x=++tot; ls=build(l,mid-1);fa[ls]=x; rs=build(mid+1,r);fa[rs]=x; pos[a[mid].v]=x; pp(x);return x; } int main(){ int n=read(); a[1].v=0,a[n+2].v=n+1; for(int i=2;i<=n+1;i++) a[i].v=read(),a[i].p=i; sort(a+2,a+n+2,cmpv); for(int i=2;i<=n+1;i++) a[i].v=i-1; sort(a+2,a+n+2,cmpp); rt=build(1,n+2); for(int i=1;i<=n;i++){ int x=pos[i];splay(x,0); printf("%d",siz[ls]);if(i^n)printf(" "); x=nxt(); int y=pos[i-1]; splay(y,0);splay(x,rt); rev[ls]^=1; } }