【CF 708C】Centroids

题目简述

给定一棵 \(n\) 个点的树,你可以删除一条边并增加一条边,形成一棵新树。

问每个点在进行这样的操作后,是否可能成为新树的重心。

\(1\le n\le4\cdot10^5\)

思路

要让每个子树大小都小于等于 \(\left\lfloor\dfrac {n} {2}\right\rfloor\),如果如果这个子树本身就可以作为重心,就不用改变。

考虑如果本身不能作为重心,说明一定有且只有一个子树大小大于 \(\left\lfloor\dfrac {n} {2}\right\rfloor\)

我们一定是从这个子树里面选一个子树接在当前的根上面,否则不是最优的。那么就要从该子树里面找到一个小于等于 \(\left\lfloor\dfrac {n} {2}\right\rfloor\) 的最大子树,然后就可以进行判断了。

考虑如何快速求出这个值。

看上去就很像一个换根 DP。

先考虑 \(dp_u\)\(u\) 子树内内该值的大小。对于他的儿子 \(v\),有如下方程:

\[f(x)= \begin{cases} \max(siz_v)& siz_v\le\left\lfloor\dfrac {n} {2}\right\rfloor\\ \max(dp_v)& \text{otherwise} \end{cases} \]

考虑换根,那我们要得到子树外能移除最大子树的大小。

考虑 \(dp'_v\) 如何得到。考虑 \(dp_u\) 的最佳转移点,如果 \(dp_u\) 最佳转移点就是 \(v\) ,那么我们就需要得到一个点第二大的能够去除的子树大小。所以必须考虑维护两个 dp 值,\(dp_{u,0}\) 表示第一大的值,\(dp_{u,1}\) 表示第二大的值。

然后如果 \(v\)\(u\) 最佳转移点,那么 \(dp'_v\) 可取值为 \(dp[u][1]\)\(n-siz_u(n-siz_u<=\left\lfloor\dfrac {n} {2}\right\rfloor)\),否则可取值为 \(dp_{u,0}\)\(n-siz_u(n-siz_u<=\left\lfloor\dfrac{n}{2}\right\rfloor)\)

代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
struct edge {
    int to,nxt;
} e[N<<1];
int n,cnt,head[N],siz[N],maxsiz[N],f[N][2],pos[N];
inline void add(int u,int v) {
    e[++cnt].nxt=head[u],head[u]=cnt,e[cnt].to=v;
}
void dfs1(int u,int fa) {
    siz[u]=1;
    for(int i=head[u]; i; i=e[i].nxt) {
        if(e[i].to==fa) {
            continue;
        }
        dfs1(e[i].to,u),siz[u]+=siz[e[i].to];
        int v=f[e[i].to][0];
        if(siz[e[i].to]>siz[maxsiz[u]]) {
            maxsiz[u]=e[i].to;
        }
        if(siz[e[i].to]<=n/2) {
            v=siz[e[i].to];
        }
        if(f[u][0]<v) {
            f[u][1]=f[u][0],f[u][0]=v,pos[u]=e[i].to;
        } else if(f[u][1]<v) {
            f[u][1]=v;
        }
    }
}
int ans[N],dp[N];
void dfs2(int u,int fa) {
    ans[u]=1;
    if(siz[maxsiz[u]]>n/2) {
        ans[u]=(siz[maxsiz[u]]-f[maxsiz[u]][0]<=n/2);
    } else if(n-siz[u]>n/2) {
        ans[u]=(n-siz[u]-dp[u]<=n/2);
    }
    for(int i=head[u]; i; i=e[i].nxt) {
        if(e[i].to==fa) {
            continue;
        }
        int v=n-siz[u];
        if(n-siz[u]>n/2) {
            v=dp[u];
        }
        dp[e[i].to]=max(dp[e[i].to],v);
        if(pos[u]==e[i].to) {
            dp[e[i].to]=max(dp[e[i].to],f[u][1]);
        } else {
            dp[e[i].to]=max(dp[e[i].to],f[u][0]);
        }
        dfs2(e[i].to,u);
    }
}
int main() {
    scanf("%d",&n);
    for(int i=1,u,v; i<=n-1; i++) {
        scanf("%d %d",&u,&v),add(u,v),add(v,u);
    }
    dfs1(1,0),dfs2(1,0);
    for(int i=1; i<=n; i++) {
        printf("%d ",ans[i]);
    }
    return 0;
}

本文作者:AFewMoon,文章地址:https://www.cnblogs.com/AFewMoon/p/15485288.html

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。

限于本人水平,如果文章有表述不当之处,还请不吝赐教。

原文地址:https://www.cnblogs.com/AFewMoon/p/15485288.html