#216d2

A. Valera and Plates  模拟

B. Valera and Contest 构造

C. Valera and Elections

http://codeforces.com/contest/369/problem/C

我的思路是首先dfs把树建起来,然后对每条需要修的边,从离树根远的那个开始向上标记,直到根节点,这样就构成了一颗新的树,新的树中的叶子节点就是所求节点,标记时候把叶子和中间节点区分开就行了。由于n比较大,要防止退化成一条链的情况,遇到标记过的,就不再向上重复标记了。

没用过邻接表,加上开始思路不是很明确,直接卡了一小时。

# include <stdio.h>
# include <vector>

using namespace std;

# define N 100005

int n;
vector <int> vec[N];

int sz[N];
int u[N], v[N], w[N];
int fa[N];

bool vis[N];
int color[N];

void dfs(int cur)
{
    for (int i = 0; i < vec[cur].size(); ++i) {
        int v = vec[cur][i];
        if (!vis[v]) {
            vis[v] = true;
            fa[v] = cur;
            dfs(v);
        }
    }
}

int main()
{
    scanf("%d", &n);
    for (int i = 0; i < n-1; ++i) {
        scanf("%d%d%d", &u[i], &v[i], &w[i]);
        vec[u[i]].push_back(v[i]);
        vec[v[i]].push_back(u[i]);
    }
    vis[1] = true;
    dfs(1);
    for (int i = 0; i < n-1; ++i) if (w[i] == 2) {
        int cur;
        if (  fa[ u[i] ] == v[i] ) {
            cur = u[i];
        }else {
            cur = v[i];
        }
        if (color[cur] == 0) {
             color[cur] = 1;
             cur = fa[cur];
             while (color[cur] <= 1) {
                 color[cur] = 2;
                 if (cur == 1) break;
                 cur = fa[cur];
             }
        } else ++color[cur];
    }
    int cnt = 0;
    for (int i = 1; i <= n; ++i) if (color[i] == 1) { ++cnt; }
    printf("%d
", cnt);
    for (int i = 1; i <= n; ++i) if (color[i] == 1) {
        printf("%d ", i);
    }
    printf("
");
    
    return 0;
}
原文地址:https://www.cnblogs.com/txd0u/p/3450563.html