题意:给一棵n个结点的树,每条边都有一种颜色,要求找出所有的good点,g点定义:从这个点出发,到其他任意结点的简单路径(最短路径),相邻的两条边颜色都不同
思路:对于某个结点O,跟他相连的结点连的边是同种颜色的话,那从这个O点往这个有重复颜色的结点遍历的时候,能遍历到的点都是不合法的,因为他们以这个O点为中心有两条相邻同颜色的边,
我用ER函数遍历不合法的子树,如果在子树中又发现了相邻同色的边,那所有图中就不包含g点了
然后我继续用solve()函数处理其他没访问的点,
//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn = 5e4 + 7;
const int maxd = 1e9 + 7;
const ll mod = 998244353;
const int INF = 0x7f7f7f7f;
int n;
struct node {
int v, c;
};
vector<node> vec[maxn];
set<int> st[maxn];
set<int> er[maxn];
int vis[maxn];
bool flag = true;
void init() {
for(int i = 1; i <= n; ++i) {
vec[i].clear();
st[i].clear();
vis[i] = 0;
}
flag = true;
}
void print1() {
printf("%d\n", n);
for(int i = 1; i <= n; ++i) {
printf("%d\n", i);
}
}
bool ER(int id, int f, int c) {
if(vis[id] == 1) return false;
vis[id] = 1;
for(auto i : vec[id]) {
if(i.v == f) continue;
if(i.c == c) return true;
if(ER(i.v, id, i.c)) return true;
}
return false;
}
void solve(int id) {
for(auto i : er[id]) {
for(auto j : vec[id]) {
if(j.c == i) {
if(ER(j.v, id, i)) {
printf("0\n");
flag = false;
return;
}
}
}
}
vis[id] = 2;
for(auto i : vec[id]) {
if(!vis[i.v]) {
solve(i.v);
}
}
}
void work() {
vector<int> ans;
for(int i = 1; i <= n; ++i) {
if(vis[i] == 2) ans.push_back(i);
}
printf("%d\n", ans.size());
for(auto i : ans) {
printf("%d\n", i);
}
}
int main() {
scanf("%d", &n);
init();
for(int i = 1; i < n; ++i) {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
vec[a].push_back(node{b, c});
vec[b].push_back(node{a, c});
if(st[a].count(c)) er[a].insert(c);
else st[a].insert(c);
if(st[b].count(c)) er[b].insert(c);
else st[b].insert(c);
}
int x = -1;
for(int i = 1; i <= n; ++i) {
if(er[i].size()) {
x = i;
break;
}
}
// cout << x << " =++= ==++ " << endl;
if(x == -1) {
print1();
}
else {
solve(x);
if(flag) {
work();
}
}
return 0;
}