这里写链接内容
在树上分块,对于一个节点如果它父亲所在的块没有被填满就把它加入它父亲所在的块,否则自成一块。在查询时对于整块直接二分查找。
Ps:因为可能会有某种数据n比较小而m比较大,所以在分块时把块的大小默认设为√n不尽合理。同时,在空间复杂度计算时,不能把块数的最大值默认为是(n+m)/√n。
代码的时空复杂度不是十分优越:
#include<bits/stdc++.h>
using namespace std;
int n,m,blocksiz,num,ans;
int a[60005],fa[60005],belong[60005];
int head[60005],block_head[10005],nex[200000],to[200000],tp;
inline void add(int _head[],int x,int y){
nex[++tp]=_head[x];
_head[x]=tp;
to[tp]=y;
}
struct Block{
int a[205],siz;
inline void Insert(int x){
int i;++siz;
for(i=siz;i>1&&a[i-1]>x;--i) a[i]=a[i-1];
a[i]=x;
}
inline void Modify(int x,int y){
int i=lower_bound(a+1,a+siz+1,x)-a;
for(;i<siz&&a[i+1]<y;++i)a[i]=a[i+1];
for(;i>1&&a[i-1]>y;--i)a[i]=a[i-1];
a[i]=y;
}
inline int Query(int x){
int loc=upper_bound(a+1,a+siz+1,x)-a;
return siz-loc+1;
}
}block[10005];
void dfs(int x){
if(block[belong[fa[x]]].siz==blocksiz) block[belong[x]=++num].Insert(a[x]),add(block_head,belong[fa[x]],num);
else block[belong[x]=belong[fa[x]]].Insert(a[x]);
for(int i=head[x];i;i=nex[i]){
if(to[i]==fa[x]) continue;
fa[to[i]]=x;dfs(to[i]);
}
}
void block_dfs(int x,int y){
ans+=block[x].Query(y);
for(int i=block_head[x];i;i=nex[i]) block_dfs(to[i],y);
}
void dfs(int x,int y){
if(a[x]>y) ++ans;
for(int i=head[x];i;i=nex[i]){
if(to[i]==fa[x]) continue;
if(belong[to[i]]^belong[x]) block_dfs(belong[to[i]],y);
else dfs(to[i],y);
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
add(head,u,v);add(head,v,u);
}
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
blocksiz=sqrt(n);
dfs(1);
scanf("%d",&m);
while(m--){
int opt,x,y;
scanf("%d%d%d",&opt,&x,&y);
x^=ans;y^=ans;
switch(opt){
case 0:{
ans=0;
dfs(x,y);
printf("%d\n",ans);
break;
}
case 1:{
block[belong[x]].Modify(a[x],y);
a[x]=y;
break;
}
case 2:{
a[++n]=y;
add(head,x,n);
fa[n]=x;
if(block[belong[x]].siz==blocksiz) block[belong[n]=++num].Insert(a[n]),add(block_head,belong[x],num);
else block[belong[n]=belong[x]].Insert(a[n]);
break;
}
}
}
}