小红的树不动点
题意:
给定一颗根为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;
}

浙公网安备 33010602011771号