Codeforces Round #379 (Div. 2) E. Anton and Tree

题目描述:戳这里
题解:
这题还是比较妙的。
我们发现有这么多的同色块,块的大小又不一样,好像无从下手。
但是我们发现一个块最多只要改一次,那么我们可以把每一个块缩成一个点(dfs一下)就省去了很多麻烦。
缩完点之后,题目就变得简单了很多,一个黑点边上只有白点,白点边上只有黑点。这就可以贪心解决,答案肯定是树的直径的一半。

代码如下:

#include
#include
#include
using namespace std;
const int maxn=200005;
int n,m,tot,sum,col[maxn],lnk[maxn],son[2*maxn],nxt[2*maxn],fa[maxn],s[maxn],dis[2][maxn];
struct dyt{
    int x,y;
}a[maxn];
void add(int x,int y){
    son[++tot]=y,nxt[tot]=lnk[x],lnk[x]=tot;
}
void clear(){
    tot=0;
    memset(lnk,0,sizeof(lnk));
    memset(nxt,0,sizeof(nxt));
}
void dfs(int x,int num){
    fa[x]=num;
    for (int j=lnk[x];j;j=nxt[j])
    if (col[son[j]]==col[x]&&!fa[son[j]]) dfs(son[j],num);
}
void dfs1(int x,int fat,int num){
    for (int j=lnk[x];j;j=nxt[j])
    if (son[j]!=fat) {
        dis[num][son[j]]=dis[num][x]+1;
        dfs1(son[j],x,num);
    }
}
void make_(){
    dfs1(1,0,0); int id=1;
    for (int i=2;i<=m;i++)
    if (dis[0][i]>dis[0][id]) id=i;
    dfs1(id,0,1); int id1=1;
    for (int i=2;i<=m;i++)
    if (i!=id&&dis[1][i]>dis[1][id1]) id1=i;
    printf("%d\n",(dis[1][id1]+1)/2);
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&col[i]);
    for (int i=1;i
        scanf("%d %d",&a[i].x,&a[i].y);
        add(a[i].x,a[i].y); add(a[i].y,a[i].x);
    }
    for (int i=1;i<=n;i++) if (!fa[i]) dfs(i,i),s[i]=++m;
    clear();
    for (int i=1;i<=n;i++)
    if (s[fa[a[i].x]]!=s[fa[a[i].y]]){
        add(s[fa[a[i].x]],s[fa[a[i].y]]);
        add(s[fa[a[i].y]],s[fa[a[i].x]]);
    }
    make_();
    return 0;
}

你可能感兴趣的:(题解,CodeForces题解)