CF734E Anton and Tree(思维+dp)

题目告诉我们连通块是一次染色的,因此我们将所有连通块缩点,这样树就变成了黑白相间且与原答案一样的树

对于这种树,我们采用贪心的策略,从树直径不断往外染色,那么染完直径就是答案。

这是因为我们直径上要黑白相间的染,这样对于其他的分支,也会不断地改变,当我们染完直径,其他不可能有比他更长的没被染色

并且直径是必须染色的,所以答案就是染完直径

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=4e5+10;
const int inf=0x3f3f3f3f;
int h[N],e[N],ne[N],idx;
vector<int> g[N];
int col[N];
int f[N][2];
int a[N];
int ans;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa){
    if(col[u]==col[fa])
        a[u]=a[fa];
    else{
        g[a[u]].push_back(a[fa]);
        g[a[fa]].push_back(a[u]);
    }
    int i;
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==fa)
            continue;
        dfs(j,u);
    }
}
int dfs1(int u,int fa){
    int i;
    f[u][0]=f[u][1]=0;
    for(i=0;i<(int)g[u].size();i++){
        int j=g[u][i];
        if(j==fa)
            continue;
        int dis=dfs1(j,u)+1;
        if(dis>=f[u][0]){
            f[u][1]=f[u][0];
            f[u][0]=dis;
        }
        else if(dis>f[u][1]){
            f[u][1]=dis;
        }
    }
    ans=max(ans,f[u][1]+f[u][0]);
    return f[u][0];
}
int main(){
    ios::sync_with_stdio(false);
    memset(h,-1,sizeof h);
    int i;
    int n;
    cin>>n;
    for(i=1;i<=n;i++){
        cin>>col[i];
        a[i]=i;
    }
    for(i=1;i<n;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    col[0]=2;
    dfs(1,1);
    dfs1(1,0);
    cout<<(ans+1)/2<<endl;
}
View Code

 

posted @ 2020-10-09 23:01  朝暮不思  阅读(102)  评论(0编辑  收藏  举报