原题解链接:https://ac.nowcoder.com/discuss/150007
块状树套上平衡树
将整块树分成好几部分,分块之后,将整棵树变成了一颗很小的树(一号树),每一个结点都是一个块,定义为二号树。
查询
查询的是一棵子树,首先,我们找到查询的结点,接着,对所属的那个块中的属于子树的结点都查询一遍,判断其权值是不是严格大于。其次,在号树对号树中的子节点所属的块进行查询。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=0;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*10+num);
(flag)&&(res=-res);
#undef num
return res;
}
const int N=100005;
struct Block{
vector<int> a;
inline void insert(int x){
a.insert(lower_bound(a.begin(),a.end(),x+1),x);
}
inline void erase(int x){
a.erase(lower_bound(a.begin(),a.end(),x));
}
inline void modify(int x,int y){
erase(x),insert(y);
}
inline int query(int x){
return a.end()-upper_bound(a.begin(),a.end(),x);
}
inline int size(){return a.size();}
}Blo[N];
int tot,ver[N<<2],head[N],Next[N<<2],first[N];
inline void add(int u,int v){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
}
inline void addb(int u,int v){
ver[++tot]=v,Next[tot]=first[u],first[u]=tot;
}
int n,B,a[N],fa[N],belong[N],bat[N],cnt;
void dfs(int u,int f){
fa[u]=f;
if(u==1||Blo[belong[f]].size()==B)
Blo[belong[u]=++cnt].insert(a[u]),addb(belong[f],belong[u]),bat[cnt]=belong[f];
else Blo[belong[u]=belong[f]].insert(a[u]);
for(int i=head[u];i;i=Next[i])
if(ver[i]!=f) dfs(ver[i],u);
}
int Y,ans=0;
void block_dfs(int u){
ans+=Blo[u].query(Y);
for(int i=first[u];i;i=Next[i])
if(bat[ver[i]]==u) block_dfs(ver[i]);
}
void find(int u,int f){
if(a[u]>Y) ++ans;
for(int i=head[u];i;i=Next[i])
if(ver[i]!=f&&fa[ver[i]]==u)
if(belong[ver[i]]==belong[u]) find(ver[i],u);
else block_dfs(belong[ver[i]]);
}
int c[N],d[N];
void cont(int u,int f){
c[++*c]=u;
for(int i=head[u];i;i=Next[i])
if(ver[i]!=f&&fa[ver[i]]==u)
if(belong[ver[i]]==belong[u]) cont(ver[i],u);
else d[++*d]=belong[ver[i]];
}
int main(){
int q,op,u,v,lastans=0;
//freopen("testdata.in","r",stdin);
n=read(),B=sqrt(n);
for(int i=1;i<n;++i)
u=read(),v=read(),add(u,v),add(v,u);
for(int i=1;i<=n;++i) a[i]=read();
dfs(1,0);q=read();
while(q--){
op=read();
switch(op){
case 0:{
u=read(),v=read();
u^=lastans,v^=lastans;
Y=v,ans=0;
find(u,fa[u]);
printf("%d\n",lastans=ans);
break;
}
case 1:{
u=read(),v=read();
u^=lastans,v^=lastans;
Blo[belong[u]].modify(a[u],v);
a[u]=v;
break;
}
case 2:{
u=read(),v=read();
u^=lastans,v^=lastans;
a[++n]=v;
add(u,n),add(n,u);
fa[n]=u;
if(Blo[belong[u]].size()==B)
Blo[belong[n]=++cnt].insert(a[n]),addb(belong[u],belong[n]),bat[cnt]=belong[u];
else Blo[belong[n]=belong[u]].insert(a[n]);
break;
}
case 3:{
u=read(),u^=lastans;
if(belong[u]!=belong[fa[u]]){
fa[u]=0,bat[belong[u]]=0;break;
}
cont(u,fa[u]);
belong[u]=++cnt;
for(int i=1;i<=*c;++i){
Blo[belong[fa[u]]].erase(a[c[i]]);
Blo[cnt].insert(a[c[i]]);
belong[c[i]]=cnt;
}
for(int i=1;i<=*d;++i)
addb(cnt,d[i]),bat[d[i]]=cnt;
fa[u]=0,*c=*d=0;
break;
}
}
}
return 0;
}