ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AIM Tech Round 3 (Div. 1)]C.Centroids

2021-12-12 20:03:08  阅读:206  来源: 互联网

标签:int uson son AIM Tech 为根 fi Div se


AIM Tech Round 3 (Div. 1)C.Centroids

题意:题意:给一棵树,问树的每个点能不能通过仅一次删边加边变成质心,所谓质心即删掉该点和相邻的边剩下的每个联通块大小都小于等于n/2。n ≤ 400000
思路:树形dp+换根dp
$umax[i]表示除了以点i为根的树,整颗大树的剩余部分中,结点数最多的子树的值$
$son[i]表示以点i为根的树的总结点数$
$uson[i]表示除了以点i为根的树,其余的总结点数$
$fi[i],se[i]表示以点i为根的树中,权值最大和次大的两颗子树对应的值$
$flag[i]标记以点i为根的树对应3种情况:为0表示所连子树中没有一个是超过n/2,可以得出该点一定可以为重心。$
$为-1 表示上方子树超过了n/2。为确切数字表示所连子树中超过了n/2$

对于每一个点,将其看为一棵树的根,如果这棵树的所有子树的结点数都小于等于$n/2$时,这个点总是可以成为重心的
如果这棵树的子树中有一棵子树 $ t $ 的结点数大于$n/2$,那么我们需要去判断如果把子树 $t$ 的$fi[t]$删去,连接到点 $i$ 是否可行
如果除了以点 $i$ 为根的树,整颗大树的剩余部分中,结点数最多的子树$t$的值大于 $n/2$ ,
同样判断如果把子树 $t$ 的$fi[t]$删去,连接到点 $i$ 是否可行。

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
typedef  long long ll;
const int inf=0x3f3f3f3f;
const int N =4e5+7,M=8e5+7;
int h[N],e[M],ne[M],idx;
void add(int a,int b){
    e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
int n,umax[N],son[N],uson[N],fi[N],se[N],flag[N],ans[N];
void dfs1(int u,int fa){
    son[u]=1;uson[u]=1;
    umax[u]=1;
    for(int i=h[u];i!=-1;i=ne[i]){
        int v=e[i];
        if(v==fa)continue;
        dfs1(v,u);
        son[u]+=son[v];
        if(son[v]>n/2)flag[u]=v;
        if(son[v]<=n/2){
            if(son[v]>fi[u])se[u]=fi[u],fi[u]=son[v];
            else if(son[v]>se[u])se[u]=son[v];
        }
        else {
            if(fi[v]>fi[u])se[u]=fi[u],fi[u]=fi[v];
            else if(fi[v]>se[u])se[u]=fi[v];
        }
    }
    uson[u]=n-son[u];
    if(uson[u]>n/2)flag[u]=-1;
}
void dfs2(int u,int fa){
    if(uson[u]<=n/2){
        umax[u]=uson[u];
    }
    else if(fi[fa]==son[u]){
        umax[u]=max(umax[fa],se[fa]);
    }
    else {
        umax[u]=max(umax[fa],fi[fa]);
    }
    for(int i=h[u];~i;i=ne[i]){
        int v=e[i];
        if(v==fa)continue;
        dfs2(v,u);
    }
}
int main(){
    cin>>n;
    memset(h,-1,sizeof h);
    memset(umax,1,sizeof umax);
    for(int i=1;i<n;i++){
        umax[i]=1;
        int a,b;cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dfs1(1,-1);
    dfs2(1,-1);
    for(int i=1;i<=n;i++){
        if(flag[i]==0)cout<<"1 ";
        else if(flag[i]==-1&&uson[i]-umax[i]<=n/2)cout<<"1 ";
        else if(flag[i]!=-1&&son[flag[i]]-fi[flag[i]]<=n/2)cout<<"1 ";
        else cout<<"0 ";
    }
    cout<<endl;
}

标签:int,uson,son,AIM,Tech,为根,fi,Div,se
来源: https://www.cnblogs.com/liang8/p/15680258.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有