原题解链接:https://ac.nowcoder.com/discuss/150007

块状树套上平衡树

将整块树分成好几部分,分块之后,将整棵树变成了一颗很小的树(一号树),每一个结点都是一个块,定义为二号树。

00查询

查询的是一棵子树,首先,我们找到查询的结点uu,接着,对uu所属的那个块中的属于uu子树的结点都查询一遍,判断其权值是不是严格大于xx。其次,在22号树对11号树中的子节点所属的块进行查询。

#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;
}