/* * rainbowRoads_sjz.cpp * * Created on: Oct 4, 2017 * Author: zeil */ #include #include #include #include #include #include using namespace std; int nV, nE, nC; typedef int Color; typedef int VertexNum; struct Edge { VertexNum source; VertexNum dest; Color color; Edge (VertexNum asource, VertexNum adest, Color acolor) : source(asource), dest(adest), color(acolor) {} }; struct Vertex { list outEdges; bool traversed; bool bad; Vertex() { traversed = false; bad = false; } int count(Color c) { auto cnt = colorCounts.find(c); if (cnt != colorCounts.end()) { return cnt->second; } else { return 0; } } int increment(Color c) { auto cnt = colorCounts.find(c); if (cnt != colorCounts.end()) { ++cnt->second; return cnt->second; } else { colorCounts[c] = 1; return 1; } } private: unordered_map colorCounts; }; Vertex* tree; unordered_set seeds; void addEdge (int source, int dest, int color) { Edge e (source, dest, color); tree[source].outEdges.push_back(e); int count = tree[source].increment(color); if (count == 2) { seeds.insert (source); } } void scheduleForTraversal (list& queue, const Edge& e) { if ((!tree[e.dest].bad) && (!tree[e.dest].traversed)) { tree[e.dest].traversed = true; tree[e.dest].bad = true; queue.push_back(e); } } void traverseAndMark(VertexNum seed) { list queue; tree[seed].traversed = true; for (Edge& e: tree[seed].outEdges) { if ((!tree[e.dest].bad) // && (!tree[e.dest].traversed) && (tree[seed].count(e.color) > 1)) { tree[e.dest].traversed = true; tree[e.dest].bad = true; queue.push_back(e); } } while (!queue.empty()) { Edge e = queue.front(); queue.pop_front(); Vertex& v = tree[e.dest]; if (seeds.count(e.dest) > 0) { //cerr << tree[seed].bad << ' ' << e.color << ' ' << v.count(e.color) << endl; if ((!tree[seed].bad) && v.count(e.color) > 1) { // This new seed v makes the original seed bad const Edge& outSeed = tree[seed].outEdges.front(); Edge inSeed (outSeed.dest, outSeed.source, outSeed.color); tree[seed].bad = true; tree[seed].traversed = true; queue.push_back(inSeed); } } for (Edge& e2: v.outEdges) { scheduleForTraversal(queue, e2); } } } void markBadNodes() { for (VertexNum seed: seeds) { traverseAndMark(seed); } } void printGoodNodes() { int goodNodeCount = 0; for (int v = 0; v < nV; ++v) { if (!tree[v].bad) { ++goodNodeCount; } } cout << goodNodeCount << endl; for (int v = 0; v < nV; ++v) { if (!tree[v].bad) { cout << v+1 << endl; } } } void solve (istream& in) { in >> nV; nE = nV - 1; nC = nE; tree = new Vertex[nV]; for (int i = 0; i < nE; ++i) { int d, s, c; in >> s >> d >> c; // Input uses 1-based counting. This code uses zero-based. --d; --s; --c; addEdge (d, s, c); addEdge (s, d, c); } markBadNodes(); printGoodNodes(); } int main (int argc, char** argv) { if (argc > 1) { ifstream in (argv[1]); solve(in); } else { solve (cin); } }