[Codeforces #379 E. Anton and Tree]缩点+树上最长路

[Codeforces #379 E. Anton and Tree]缩点+树上最长路

1. 题目链接

[Codeforces #379 E. Anton and Tree]

2. 题意描述

给定一个 N 个节点的树。树上每个节点i都有初始颜色 colori (01) , 相同颜色的且相邻的节点在同一个块中。每次操作可以将一个块中的所有节点颜色反转。问,将该树上所有节点颜色都变成0或者都变成1所需要的最少操作次数。

3. 解题思路

首先对原树用并查集缩点,并形成新的树。然后两次dfs求出树上最长链。以最长链的中点向两边扩散可能是最少的操作次数。那么答案就是树上最长链/2【向上取整】。

4. 实现代码

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
typedef pair<int, int> PII;

const int MX = 200000 + 5;

int n, color[MX];;

set<int> edge[MX];
int belong[MX];

int F(int x) { return -1 == belong[x] ? x : belong[x] = F(belong[x]); }
inline void U(int u, int v) {
    u = F(u), v = F(v);
    if(u != v) belong[v] = u;
}
/**
 * 两次DFS求树上最长路 
 */
void dfs(int u, int pre, int dep, int& d, int& id) {
    int v;
    if(dep > d) {
        d = dep;
        id = u;
    }
    for(set<int>::iterator it = edge[u].begin(); it != edge[u].end(); it++) {
        v = *it;
        if(v == pre) continue;
        dfs(v, u, dep + 1, d, id);
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
#endif // ONLINE_JUDGE
    int u, v;
    memset(belong, -1, sizeof(belong));
    cin >> n;
    for(int i = 1; i <= n; i++) cin >> color[i];
    vector<PII> I(n);
    for(int i = 1; i <= n - 1; i++) {
        cin >> u >> v; I[i] = make_pair(u, v);
        if(color[u] == color[v]) U(u, v);
    }
    set<int> node;
    for(int i = 1; i <= n - 1; i++) {
        u = F(I[i].first), v = F(I[i].second);
        node.insert(u);
        if(u == v) continue;
        node.insert(v);
        edge[u].insert(v);
        edge[v].insert(u);
    }
    int ans = 0, id;
    if(node.size() > 1) {
        dfs(F(1), -1, 0, ans, id);
        dfs(id, -1, 0, ans, id);
        ans = (ans + 1) >> 1;
    }
    cout << ans << endl;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值