CF734E Anton and Tree

题意:

一棵树上有黑白两种颜色的结点,每次可以把连通的一种颜色变成另一种颜色。求至少要多少次,才能是整棵树变为一种颜色。


因为一次操作后是整个同色连通块同时变色,那就先把同色连通块缩成一个点

缩完点后,求直径 \(d\) ,答案为 \(\lfloor \frac {d+1}2 \rfloor\)

but why?

缩完点后的图上每两个相邻的点颜色一定不同,否则应该变成1个点了

要算直径的原因是,直径是树中最长的路径,你无论怎么操作总不可能把直径都变成同一种颜色而还有其他路径非同色吧

那么直接考虑如何把直径变成同一种颜色了。肯定是从直径的中间部分开始操作。我们来模拟一下

1 0 1 0 1 0 // 0 changes
1 0 [0] 0 1 0 // 1 changes
1 1 [1] 1 1 0 // 2 changes
0 0 [0] 0 0 0 // 3 changes

然后你再模拟发现直径长度为7要4次,长度为8要4次,长度为9要5次

于是你就找到了规律(华生,你发现了盲点

// This code wrote by chtholly_micromaker(MicroMaker)
#include <bits/stdc++.h>
#define reg register
#define pii pair<int,int>
using namespace std;
const int MaxN=200050;
struct Edge
{
    int nxt,to;
}E[MaxN<<1],Ep[MaxN<<1];
template <class t> inline void rd(t &s)
{
    s=0;
    reg char c=getchar();
    while(!isdigit(c))
        c=getchar();
    while(isdigit(c))
        s=(s<<3)+(s<<1)+(c^48),c=getchar();
    return;
}
int hd[MaxN],hdp[MaxN],en,enp,n;
int col[MaxN],idp[MaxN];
bool vis[MaxN];
pii dis[MaxN];
inline void adde(int u,int v)
{
    ++en;
    E[en].nxt=hd[u];
    E[en].to=v;
    hd[u]=en;
    return;
}
inline void addep(int u,int v)
{
//  cout<<"addep: "<<u<<" -> "<<v<<endl;
    ++enp;
    Ep[enp].nxt=hdp[u];
    Ep[enp].to=v;
    hdp[u]=enp;
    return;
}
inline void dfs1(int u,int color,int idx)
{
    vis[u]=true;
    idp[u]=idx;
    for(int i=hd[u];~i;i=E[i].nxt)
    {
        reg int v=E[i].to;
        if(vis[v])
            continue;
        if(col[v]!=color)
            continue;
        dfs1(v,color,idx);
    }
    return;
}
inline void dfs2(int u,int color,int idx)
{
    if(col[u]!=color)
    {
        addep(idp[u],idx);
        addep(idx,idp[u]);
        return;
    }
    vis[u]=true;
    for(int i=hd[u];~i;i=E[i].nxt)
    {
        reg int v=E[i].to;
        if(vis[v])
            continue;
        dfs2(v,color,idx);
    }
    return;
}
inline void dfs3(int u,int fa)
{
    for(int i=hdp[u];~i;i=Ep[i].nxt)
    {
        reg int v=Ep[i].to;
        if(v==fa)
            continue;
        dis[v].first=dis[u].first+1;
        dfs3(v,u);
    }
    return;
}
signed main(void)
{
    ios::sync_with_stdio(false);cin.tie(0);
    memset(hd,-1,sizeof hd);
    memset(hdp,-1,sizeof hdp);
    reg int u,v,cnt=0;
    cin>>n;
    for(int i=1;i<=n;++i)
        cin>>col[i];
    for(int i=1;i<n;++i)
    {
        cin>>u>>v;
        adde(u,v);adde(v,u);
    }
    for(int i=1;i<=n;++i)
        if(!vis[i])
            dfs1(i,col[i],++cnt);
    memset(vis,false,sizeof vis);
    for(int i=1;i<=n;++i)
        if(!vis[i])
            dfs2(i,col[i],idp[i]);
    for(int i=1;i<=cnt;++i)
        dis[i].second=i;
    dfs3(1,0);
    dis[1].first=0;
    reg pii res=dis[1];
    for(int i=2;i<=cnt;++i)
        if(dis[i].first>res.first)
            res=dis[i];
    dis[res.second].first=0;
    dfs3(res.second,0);
    res=dis[1];
    for(int i=2;i<=cnt;++i)
        if(dis[i].first>res.first)
            res=dis[i];
    cout<<(res.first+1)/2<<endl;
    /*
    for(int i=1;i<=n;++i)
        cout<<idp[i]<<" ";
    */
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/chinesepikaync/p/12403386.html
今日推荐