[BZOJ 3720] Gty的妹子树
Link:
Solution:
由于强制在线+新添节点,主席树难以进行更新
这时考虑在树上分块,具体内部的操作和在序列上相同
每次通过判断父节点块的大小判断是否要新开一块
注意每一块在树上都是连续的,这样在查询时子树时保证最后全是整块
不过由于上一条特性导致遇到菊花图就将每一块大小卡到了1
复杂度稳定的算法其实是对修改操作进行分块:
每$sqrt(q)$次修改后就暴力重构主席树,复杂度$O(n*log(n)*sqrt(n))$
每次查询先找到上次暴力重构的结果,再对之后的$sqrt(q)$次询问用倍增找到其对答案的影响
这样总复杂度是稳定的$O(n*log(n)*sqrt(n))$
Code:
#include <bits/stdc++.h> using namespace std; #define X first #define Y second #define pb push_back typedef double db; typedef long long ll; typedef pair<int,int> P; const int MAXN=6e4+10,SIZE=305; struct BLOCK { int a[310],size; void Insert(int x) { a[++size]=x; for(int i=size;i>1;i--) if(a[i-1]>a[i]) swap(a[i],a[i-1]); } void Update(int x,int val) { int pos=lower_bound(a+1,a+size+1,x)-a; a[pos]=val; for(int i=pos;i>=2;i--) if(a[i-1]>a[i]) swap(a[i],a[i-1]); for(int i=pos;i<=size-1;i++) if(a[i]>a[i+1]) swap(a[i],a[i+1]); } int Query(int x) {return size-(upper_bound(a+1,a+size+1,x)-a-1);} }bl[MAXN]; struct edge{int nxt,to;} e[MAXN<<2],eb[MAXN<<2]; int n,q,op,x,y,sub[MAXN],w[MAXN],f[MAXN]; int cnt,tot,totb,head[MAXN],headb[MAXN],res; inline int read() { char ch;int num,f=0; while(!isdigit(ch=getchar())) f|=(ch=='-'); num=ch-'0'; while(isdigit(ch=getchar())) num=num*10+ch-'0'; return f?-num:num; } void add(int x,int y) {e[++tot]=(edge){head[x],y};head[x]=tot;} void addb(int x,int y) {eb[++totb]=(edge){headb[x],y};headb[x]=totb;} void dfs(int x,int anc) { if(bl[sub[anc]].size==SIZE) { bl[++cnt].Insert(w[x]); addb(sub[anc],cnt);sub[x]=cnt; } else sub[x]=sub[anc],bl[sub[anc]].Insert(w[x]); for(int i=head[x];i;i=e[i].nxt) if(e[i].to!=anc) f[e[i].to]=x,dfs(e[i].to,x); } int calblock(int x,int val) { int ret=bl[x].Query(val); for(int i=headb[x];i;i=eb[i].nxt) ret+=calblock(eb[i].to,val); return ret; } int cal(int x,int val) { int ret=(w[x]>val); for(int i=head[x];i;i=e[i].nxt) { if(e[i].to==f[x]) continue; if(sub[e[i].to]==sub[x]) ret+=cal(e[i].to,val); else ret+=calblock(sub[e[i].to],val); } return ret; } int main() { n=read(); for(int i=1;i<n;i++) x=read(),y=read(),add(x,y),add(y,x); for(int i=1;i<=n;i++) w[i]=read(); dfs(1,0); q=read(); while(q--) { op=read();x=read();y=read(); x^=res;y^=res; if(op==0) printf("%d\n",res=cal(x,y)); else if(op==1) { bl[sub[x]].Update(w[x],y); w[x]=y; } else { w[++n]=y;f[n]=x; add(x,n);add(n,x); if(bl[sub[x]].size==SIZE) { sub[n]=++cnt; bl[cnt].Insert(y); addb(sub[x],cnt); } else { sub[n]=sub[x]; bl[sub[x]].Insert(y); } } } return 0; }