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

题意:
给一颗树 每个节点有黑白2色
可以使一个色块同事变色,问最少的变色次数。
思路:
先缩点 把一样颜色的相邻点 缩成一个
然后新的树 刚好每一层是一个颜色。
最后的答案就是树的直径/2

不过我用的树上的dp,强行求了以每个点为根时树的深度
答案就是最小的深度-1

 

具体见代码:

const int maxn = 200000 + 10;
int n;
int color[maxn];
int pa[maxn];
vector<int> G[maxn], G2[maxn];
void init()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", color + i);
    }
    int u, v;
    for (int i = 1; i < n; i++)
    {
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
}

int find(int x) 
{ 
    return pa[x] != x ? pa[x] = find(pa[x]) : x;
}

int fa[maxn];
void getTree()
{
    queue<int> q;
    q.push(1);
    color[0] = -1;
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        if (color[fa[u]] == color[u]) pa[u] = find(fa[u]);
        else G2[fa[pa[u]]].push_back(u);
        for (int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if (find(v) == find(fa[u])) continue;
            fa[v] = pa[u];
            q.push(v);
        }
    }
    swap(G, G2);
}

void pg()
{
    cout << "Graph:" << endl;
    for (int i = 0; i <= n; i++)
    {
        for (int j = 0; j < G[i].size(); j++)
        {
            cout << i << " " << G[i][j] << endl;
        }
    }
}

int son1[maxn], son2[maxn]; //i节点的最大的儿子 和 次大的儿子的下标

int deep[maxn]; 
int deepFa[maxn];//i的父亲除了i以外的最深深度

int d[maxn];//以i为根时树的深度 d[i] = max(deep[i], deepFa[i] + 1)

int dfs(int u) //得到每个节点最深儿子的深度
{
    deep[u] = 0;
    for (int i = 0; i < G[u].size(); i++)
    {
        int v = G[u][i];
        fa[v] = u;
        int tmp = dfs(v);
        if (tmp >= deep[u])
        {
            son2[u] = son1[u];
            son1[u] = v;
            deep[u] = tmp;
        }
        else
        {
            if (tmp > deep[son2[u]]) son2[u] = v;
        }
    }
    deep[u]++;
    return deep[u];
}

int bfs()
{
    queue<int> q;
    for (int i = 0; i < G[1].size(); i++) q.push(G[1][i]);
    int ans = d[1] = deep[1];
    while (!q.empty())
    {
        int u = q.front(); q.pop();
        if (son1[fa[u]] == u) deepFa[u] = deep[son2[fa[u]]] + 1;
        else deepFa[u] = deep[son1[fa[u]]] + 1;

        deepFa[u] = max(deepFa[u], deepFa[fa[u]] + 1);

        d[u] = max(deep[u], deepFa[u] + 1);
        ans = min(ans, d[u]);
        for (int i = 0; i < G[u].size(); i++)
        {
            q.push(G[u][i]);
        }
    }
    return ans - 1;
}

void solve()
{
    for (int i = 1; i <= n; i++) pa[i] = i;
    getTree();
    memset(fa, -1, sizeof(fa));
    for (int i = 0; i <= n; i++) son1[i] = son2[i] = n + 1;
    dfs(0);
    cout << bfs() << endl;
}

int main()
{
    init();
    solve();
    return 0;
}

 

posted @ 2016-11-17 15:33  llysrv  阅读(150)  评论(0编辑  收藏  举报