[bzoj3720]Gty的妹子树
这道题还有一种分块的做法:每当发现当前子树中有K个点,就将这K个点合在一起,然后把每个块内的节点权值排序(虽然这个算法并没有保证块的个数,但是由于数(shen)据(qi)随(hai)机(luo),所以不妨设为n/K)。
操作0:对于每一个块暴力查询(构建一颗虚树),然后对根所在块暴力,时间复杂度o(K+n/K)。
操作1:暴力修改该权值并排序(可以插入,也可以直接sort)
操作2:当添加节点父亲所在块节点个数不到K,直接加入该块,否则单独成块,注意维护节点信息。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define siz 300 4 #define N 100005 5 struct ji{ 6 int nex,to; 7 }edge[N<<1]; 8 int E,n,m,x,y,s,p,z,ans,head[2][N],bl[N],f[N],w[N],se[N/3][siz+10]; 9 void add(int x,int y,int p){ 10 edge[E].nex=head[p][x]; 11 edge[E].to=y; 12 head[p][x]=E++; 13 } 14 void dfs(int k,int fa){ 15 f[k]=fa; 16 if (se[bl[fa]][0]==siz)add(bl[fa],++s,1); 17 bl[k]=s; 18 se[s][++se[s][0]]=w[k]; 19 for(int i=head[0][k];i!=-1;i=edge[i].nex) 20 if (edge[i].to!=fa)dfs(edge[i].to,k); 21 } 22 void dfs2(int k){ 23 ans+=se[k]+se[k][0]+1-upper_bound(se[k]+1,se[k]+se[k][0]+1,y); 24 for(int i=head[1][k];i!=-1;i=edge[i].nex)dfs2(edge[i].to); 25 } 26 void calc(int k,int fa,int p){ 27 if (bl[k]!=p){ 28 dfs2(bl[k]); 29 return; 30 } 31 if (w[k]>y)ans++; 32 for(int i=head[0][k];i!=-1;i=edge[i].nex) 33 if (edge[i].to!=fa)calc(edge[i].to,k,p); 34 } 35 int main(){ 36 scanf("%d",&n); 37 memset(head,-1,sizeof(head)); 38 for(int i=1;i<n;i++){ 39 scanf("%d%d",&x,&y); 40 add(x,y,0); 41 add(y,x,0); 42 } 43 s++; 44 for(int i=1;i<=n;i++)scanf("%d",&w[i]); 45 dfs(1,0); 46 for(int i=1;i<=s;i++)sort(se[i]+1,se[i]+se[i][0]+1); 47 scanf("%d",&m); 48 for(int i=1;i<=m;i++){ 49 scanf("%d%d%d",&p,&x,&y); 50 x^=ans; 51 y^=ans; 52 if (!p){ 53 ans=0; 54 calc(x,f[x],bl[x]); 55 printf("%d\n",ans); 56 } 57 if (p==1){ 58 z=bl[x]; 59 se[z][lower_bound(se[z]+1,se[z]+se[z][0]+1,w[x])-se[z]]=y; 60 sort(se[z]+1,se[z]+se[z][0]+1); 61 w[x]=y; 62 } 63 if (p==2){ 64 w[++n]=y; 65 add(x,n,0); 66 f[n]=x; 67 if (se[bl[x]][0]==siz)bl[n]=++s; 68 else bl[n]=bl[x]; 69 z=bl[n]; 70 se[z][++se[z][0]]=y; 71 if (z!=bl[x])add(bl[x],z,1); 72 sort(se[z]+1,se[z]+se[z][0]+1); 73 } 74 } 75 }