来自FallDream的博客,未经允许,请勿转载,谢谢。
题意:给你一棵树,有点权,要求支持三个操作:1)单点修改 2)插入一个点 3)询问子树内权值大于一个数的节点个数。
n,m<=30000
去网上搜了一下,发现大家都是块状树啊,还有像带插区间k大那样的替罪羊套treap之类的。但是我写了一个很奇怪的做法
首先很容易想到主席树之类的,建一次主席树是nlogn的
然后我们把修改操作全部压到一个栈里面,询问的时候把栈遍历一遍计算答案;每当操作到达一定数量的时候,重建整棵树。
假设操作到达k之后重建,复杂度是$O(frac{n}{k}*nlogn+m(k+logn))$
k取到大约$sqrt{nlogn}$的时候复杂度最小 灰常科学啊
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define MN 60000 #define INF 2147483647 #define ll long long using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } struct edge{int to,next;}e[MN*2+5]; struct Tree{int l,r,x;}T[5000000]; struct operation{int kind,x,y,z;}q[MN+5]; int cnt,n,en=0,head[MN+5],last=0,top,nl[MN+5],nr[MN+5],dn=0,m,sz,p[MN+5],a[MN+5],rt[MN+5]; bool b[MN+5]; void ins(int f,int t) { e[++en]=(edge){t,head[f]};head[f]=en; e[++en]=(edge){f,head[t]};head[t]=en; } void dfs(int x,int f) { p[nl[x]=++dn]=x; for(int i=head[x];i;i=e[i].next) if(e[i].to!=f) dfs(e[i].to,x); nr[x]=dn; } void ins(int x,int nx,int k) { int l=0,r=INF,mid; while(l<r) { mid=((ll)l+r)>>1; if(k<=mid) { T[nx].r=T[x].r;T[nx].l=++cnt; r=mid;x=T[x].l;nx=T[nx].l; } else { T[nx].l=T[x].l;T[nx].r=++cnt; l=mid+1;x=T[x].r;nx=T[nx].r; } T[nx].x=T[x].x+1; } } int query(int x,int nx,int k) { int sum=0,l=0,r=INF,mid; while(l<r) { mid=((ll)l+r)>>1; if(k>mid) x=T[x].r,nx=T[nx].r,l=mid+1; else sum+=T[T[nx].r].x-T[T[x].r].x,r=mid,x=T[x].l,nx=T[nx].l; } return sum+T[nx].x-T[x].x; } void build() { dn=cnt=0;dfs(1,0); for(int i=1;i<=n;i++) ins(rt[i-1],rt[i]=++cnt,a[p[i]]); } int main() { n=read();sz=sqrt(15*n); for(int i=1;i<n;i++) ins(read(),read()); for(int i=1;i<=n;i++) a[i]=read(); build();m=read(); for(int i=1,ad=0;i<=m;i++) { int op=read(),x=read()^last,y=read()^last; if(op==0) { if(x<=n) { int ans=(y==INF?0:query(rt[nl[x]-1],rt[nr[x]],y+1)); for(int j=1;j<=top;j++) if(q[j].kind==1) { if(q[j].x<=n&&nl[q[j].x]>=nl[x]&&nl[q[j].x]<=nr[x]) ans=ans-(q[j].y>y)+(q[j].z>y); } else { if((b[q[j].y]&&q[j].y>n)||(q[j].y<=n&&nl[q[j].y]>=nl[x]&&nl[q[j].y]<=nr[x])) b[q[j].x]=1; else b[q[j].x]=0; } for(int j=1;j<=ad;j++) if(b[n+j]) ans+=(a[n+j]>y); printf("%d ",last=ans); } else { int ans=0; for(int j=1;j<=top;j++) if(q[j].kind==2) { if((b[q[j].y]&&q[j].y>n)||q[j].x==x) b[q[j].x]=1; else b[q[j].x]=0; } for(int j=1;j<=ad;j++) if(b[n+j]) ans+=(a[n+j]>y); printf("%d ",last=ans); } } else if(op==1) q[++top]=(operation){1,x,a[x],y},a[x]=y; else q[++top]=(operation){2,n+(++ad),x,0},ins(n+ad,x),a[n+ad]=y; if(top>=sz) n+=ad,top=0,ad=0,build(); } return 0; }