小红的树不动点

题意:

给定一颗根为n的树,求子树不动点数量之和

思路:

不妨从1结点往上跳,每到一个新的根节点计算子树mex值的变化

因为mex单调递增,故可以通过暴力枚举+lca(u,v)=u来判断

void solve(){
    int n;cin>>n;
    vector<vector<int>>e(n+1);
    rep(i,1,n-1){
        int u,v;cin>>u>>v;
        e[u].pb(v);e[v].pb(u);
    }
    int ans=0;
    vector<int>dp(n+1);
    vector<int>f(n+1);
    vector<int>depth(n+1);
    auto dfs = [&](auto&&self,int u,int fa)->void{
        f[u]=fa;
        depth[u]=depth[fa]+1;
        for(int v:e[u]){
            if(v==fa)continue;
            self(self,v,u);
        }
    };
    depth[0]=-1;
    dfs(dfs,n,0);
    int x=1;
    int res=1;
    vector<vector<int>>anc(n+1,vector<int>(26));
    rep(i,1,n)anc[i][0]=f[i];
    rep(i,1,26){
        rep(j,1,n){
            anc[j][i]=anc[anc[j][i-1]][i-1];
        }
    }
    auto lca =[&](int u,int v)->int{
        if(depth[v]>depth[u])swap(u,v);
        for(int i=25;i>=0;i--){
            if(depth[anc[u][i]]>=depth[v]){
                u=anc[u][i];
            }
            if(u==v)return v;
        }
        for(int i=25;i>=0;i--){
            if(anc[u][i]!=anc[v][i]){
                u=anc[u][i];
                v=anc[v][i];
            }
        }
        return anc[u][0];
    };
    while(1){
        ans+=res;
        for(int i=res+1;i<=n;i++){
            if(lca(i,x)!=x)break;
            ans++;
            res++;
        }
        if(x==n)break;
        x=f[x];
    }
    cout<<ans<<endl;
}
posted @ 2025-08-10 22:20  Marinaco  阅读(16)  评论(0)    收藏  举报
//雪花飘落效果