CodeForces - 734E - Anton and Tree

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40032278/article/details/81556713

题目

给出n个点,n-1条边构成一棵生成树,每个点都有黑白两种颜色,每次改变颜色都能使同颜色的相邻点改变颜色,求最小改变颜色的次数

题解

  1. 每次将一个联通块的颜色反转,这个联通块的区域都会变的更大。
  2. 所以只要把颜色相同的点缩成一个点
  3. 只要在缩完点的树的直径中心改变len / 2个节点即可
  4. len 为直径长度
#include<bits/stdc++.h>
using namespace std;
int head[400010],cnt,v[400010],c[400010],p[400010],d[400010];
pair<int, int> b[400010];
struct node
{
    int to,next;
} a[400010];
void add(int u,int vv)
{
    cnt++;
    a[cnt].to=vv;
    a[cnt].next=head[u];
    head[u]=cnt;
}
void ddd(int u,int fa)
{
    v[u]=1;
    p[u]=fa;
    for(int i=head[u]; i!=-1; i=a[i].next)
    {
        int vv=a[i].to;
        if(c[vv]!=c[u]||v[vv]) continue;
        ddd(vv,fa);
    }
}
void dfs(int u,int fa)
{
    for(int i=head[u]; i!=-1; i=a[i].next)
    {
        int vv=a[i].to;
        if(vv==fa) continue;
        d[vv]=d[u]+1;
        dfs(vv,u);
    }
}
int main()
{
    int n,i,x,ans=0;
    cnt=0;
    scanf("%d",&n);
    memset(head,-1,sizeof(head));
    memset(v,0,sizeof(v));
    for(i=1; i<=n; i++) scanf("%d",&c[i]);
    for(i=1; i<n; i++)
    {
        scanf("%d%d",&b[i].first,&b[i].second);
        add(b[i].first,b[i].second);
        add(b[i].second,b[i].first);
    }
    for(i=1; i<=n; i++)
    {
        if(v[i]==0) ddd(i,i);
    }
    memset(head,-1,sizeof(head));
    cnt=0;
    for(i=1; i<n; i++)
    {
        if(p[b[i].first]!=p[b[i].second])
        {
            add(p[b[i].first],p[b[i].second]);
            add(p[b[i].second],p[b[i].first]);
        }
    }
    x=p[1];
    d[p[1]]=1;
    dfs(p[1],-1);
    for(i=1; i<=n; i++)
        if(p[i]==i&&d[i]>d[x]) x=i;
    d[x]=1;
    dfs(x,-1);
    for(i=1; i<=n; i++)
        if(p[i]==i&&d[i]>ans) ans=d[i];
    printf("%d\n", ans/2);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40032278/article/details/81556713