1. 程式人生 > 其它 >【CF 708C】Centroids

【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 國際許可協議 進行許可。

限於本人水平,如果文章有表述不當之處,還請不吝賜教。