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

http://codeforces.com/contest/734/problem/E
http://codeforces.com/blog/entry/48397
打CF,才知道自己和世界玩ACM的人的差距。
当然了,只要是打比赛,都知道。
——
这题题意是
一棵树,每个点有黑白两色,每一次染色,可以把这一片和周围其它和它相同的颜色变色,问搞几次变成同一种颜色。
——
比赛的时候我居然想的是要么白的全变黑,要么黑的全变白,DFS,真是Naive
——
实际上应该可以黑变白,白再变黑,这样可能次数更少
——
算法第一步首先压缩图形,把相同颜色且相连的点变成一个点。这样显然不改变ANS。
那么图肯定是一个一黑一白一黑一白交错相连的树
那么最佳方案肯定是从最中心的那个点开始变色,每次变成和旁边的点的颜色相同,这样就可以压缩,然后再变
ans = (d + 1) / 2 d为树上最长两个点的距离
我们当然可以枚举每一个点DFS把这个d给找出来
不过题解给了一个更为优化的方法,并且大多数人都是这么写的,莫非这是一个经典的问题?
well-known问题
不过我也不得而知了
这个优化算法是
从根开始往下走,每到一个点,不往回走了
继续往下走,那么肯定可以找到以这个点为根的最大距离,但是最长距离可能不包括根
不过肯定是以这个点为根的最大距离和第二大距离之和
——

#define LOG(x) cout << #x << " = " << (x) << endl
#define PRINTLN(x) cout << (x) << endl
#define MEM(x, y) memset((x), (y), sizeof((x)))
#include <bits/stdc++.h>
using namespace std;
const double PI = 2*acos(0);
typedef long long ll;
typedef complex<double> Complex;
int nextInt()
{
  int x;
  scanf("%d", &x);
  return x;
}
ll nextLL()
{
  ll x;
  scanf("%lld", &x);
  return x;
}
//TEMPLATE

//MAIN
const int MAXN = 200000;
int color[MAXN];
vector<int> g[MAXN];
bool vis[MAXN];
int lv[MAXN];
vector<int> g1[MAXN];
int n;
void dfs(int u, int c, int l)
{
  for (int i = 0; i < g[u].size(); i++) {
    int v = g[u][i];
    if (vis[v] || color[v] != c) continue;
    vis[v] = true;
    lv[v] = l;
    dfs(v, c, l);
  }
}
int ans;
int dfs1(int u, int p) // p is parent
{
  int max1 = 0, max2 = 0;
  for (int i = 0; i < g1[u].size(); i++) {
    int v = g1[u][i];
    if (v == p) continue;
    max2 = max(max2, dfs1(v, u) + 1);
    if (max1 < max2) swap(max1, max2);
  }
  ans = max(ans, max1 + max2);
  return max1;
}
void solve()
{
  for (int i = 0; i < n; i++) {
    color[i] = nextInt();
    g[i].clear();
    g1[i].clear();
  }
  for (int i = 0; i < n - 1; i++) {
    int u = nextInt() - 1, v = nextInt() - 1;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  MEM(vis, false);
  int l = 0;
  for (int i = 0; i < n; i++) {
    if (!vis[i]) {
      vis[i] = true;
      lv[i] = l;
      dfs(i, color[i], l++);
    }
  }
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < g[i].size(); j++) {
      int v = g[i][j];
      if (lv[i] != lv[v]) {
        g1[lv[i]].push_back(lv[v]);
      }
    }
  }
  ans = 0;
  dfs1(0, -1);
  cout << (ans + 1) / 2 << endl;
}
int main()
{
  //freopen("in.txt", "r", stdin);
  while (scanf("%d", &n) != EOF) {
    solve();
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值