Codeforces 734E. Anton and Tree By Assassin 缩点+树的最大直径

题意就不多加赘述了,说白了就是每一次可以反转任意连通块儿,这个连通块儿必须满足相连且花色相同,问你最少的反转次数。

思路:一看题目思路其实很清楚了,我们为了缩小数据规模,利用缩点将一个连同块儿化成一个点,之后我们一定可以得到一个树,因为原题就是一个树,之后我们只需要找到树的最大直径就行了。
步骤1:缩点
步骤2:求树的最大直径(其实就是两次搜索,因为第一次从任意点出发找到最远的一个点,那么这个点一定是树直径上两端的一个点,第二次再从这个点出发找到最远的点的距离就是树的直径了。)

第一次写缩点,丑了点。。。

#include<bits/stdc++.h>
#define input freopen("input.txt","r",stdin)
using namespace std;
const int maxn = 200002;
vector<int>vec[maxn],change[maxn];
int vis[maxn]={0},color[maxn]={0},belong[maxn]={0};  // belong代表改点归并到第几个缩点 
int n,suo_size=0,ans=maxn,fathur=0;

void dfs(int pos,int number){
    int i;
    vis[pos]=1;
    belong[pos]=number;
    for(i=0;i<vec[pos].size();i++){
        if(vis[vec[pos][i]]==0&&color[vec[pos][i]]==color[pos]){
            dfs(vec[pos][i],number);
        }
    }
}
void DFS(int pos){
    int i;
    vis[pos]=1;
    for(i=0;i<vec[pos].size();i++){
        if(vis[vec[pos][i]]==0&&color[vec[pos][i]]==color[pos]){
            DFS(vec[pos][i]);
        }
        else if(vis[vec[pos][i]]==0&&color[vec[pos][i]]!=color[pos]){
            change[belong[vec[pos][i]]].push_back(belong[pos]);
            change[belong[pos]].push_back(belong[vec[pos][i]]);
        }
    }
}
void dps(int pos,int length){
    int i,flag=1;
    vis[pos]=1;
    for(i=0;i<change[pos].size();i++){
        if(vis[change[pos][i]]==0){
            dps(change[pos][i],length+1);
            flag=0;
        }
    }
    if(flag==1){
        if(ans<length){
            ans=length;
            fathur=pos;
        }
    }
    return ;
}
int main(){
    int i,j,l,r;
    while(scanf("%d",&n)!=EOF){
        for(i=1;i<=n;i++) scanf("%d",&color[i]);
        for(i=1;i<=n-1;i++){
            scanf("%d%d",&l,&r);
            vec[l].push_back(r); vec[r].push_back(l);
        }
        memset(vis,0,sizeof(vis));  //其实大多ACM写成一次处理的,我喜欢加上EOF操作,所以vis要经常初始化,就慢了 

        for(suo_size=0,i=1;i<=n;i++){  //这次dfs将连通块儿缩到一个点 
            if(vis[i]==0){
                suo_size++;
                dfs(i,suo_size);
            }
        }

        memset(vis,0,sizeof(vis));
        for(i=1;i<=n;i++){              //这次DFS将缩点后树连接起来 
            if(vis[i]==0) DFS(i);
        }
        memset(vis,0,sizeof(vis));

        ans=0; fathur=0;            //求树的直径 
        dps(1,0);
        ans=0;                      //第一次的ans求出来没用。。。 
        memset(vis,0,sizeof(vis));  //记得初始化 访问数组 
        dps(fathur,0);

        cout<<(ans+1)/2<<endl;      //结果先加1因为有奇偶情况,ans求的是两端最远距离,还要加上自己才是直径 
    }
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值