#include #define FOR(i, n) for(lli i = 0; i < (lli)(n); ++i) #define X(A) get<0>(A) #define Y(A) get<1>(A) #define Z(A) get<2>(A) #define W(A) get<3>(A) #define mt make_tuple using namespace std; using lli = long long int; using pii = tuple; using piii = tuple; using vi = vector; using vii = vector; using viii = vector; using vvi = vector; using vvii = vector; using vviii = vector; using vb = vector; using vvb = vector; /** WARNING ** ************* This algorithm considers the graph to have no self-pointing edge, ie. no edge (u, u) */ const int INFTY = 1000*1000*1000; // FIXME large enough for this problem? struct Edge { int from, to; int weight; Edge() {} Edge(int from, int to, int weight): from(from), to(to), weight(weight) {} }; struct Vert { int selfId; int ufFather; int ufHeight; vector out; vector in; int parentEdge; bool suppressed; Vert(int id): selfId(id), ufFather(id), ufHeight(1), parentEdge(-1), suppressed(false) {} }; int root; vector edges; vector vertices; int cost = 0; int ufFind(int vert) { Vert& v = vertices[vert]; if(v.ufFather == vert) return vert; v.ufFather = ufFind(v.ufFather); return v.ufFather; } void ufUnion(int iv1, int iv2) { iv1 = ufFind(iv1); iv2 = ufFind(iv2); Vert& v1 = vertices[iv1]; Vert& v2 = vertices[iv2]; if(v1.ufHeight < v2.ufHeight) v1.ufFather = iv2; else if(v2.ufHeight < v1.ufHeight) v2.ufFather = iv1; else { v1.ufFather = iv2; v2.ufHeight++; } } void buildMst(int vertId) { printf("> %d\n", vertId); Vert& vert = vertices[vertId]; int minIncWeight = INFTY; int minId = -1; for(int incEdge: vert.in) { Edge& edge = edges[incEdge]; if(minIncWeight > edge.weight) { minIncWeight = edge.weight; minId = incEdge; } } if(minId == -1) { assert(vertId == root); return; } for(int incEdge: vert.in) { Edge& edge = edges[incEdge]; edge.weight -= minIncWeight; } cost += minIncWeight; vert.parentEdge = minId; int parent = edges[minId].from; int parentCmp = ufFind(parent), selfCmp = ufFind(vertId); if(parentCmp == selfCmp) { // Build current cycle vector cycle; cycle.push_back(parent); while(cycle.back() != vertId) cycle.push_back(edges[vertices[cycle.back()].parentEdge].from); vertices.push_back(Vert(vertices.size())); Vert& condensed = vertices.back(); printf("Compressing into %d: ", condensed.selfId); for(int cyc: cycle) printf("%d ", cyc); puts(""); vector nInEdges, nOutEdges; for(int cycleVert: cycle) { Vert& v = vertices[cycleVert]; v.suppressed = true; for(int inEdge: v.in) { edges[inEdge].to = condensed.selfId; nInEdges.push_back(inEdge); } for(int outEdge: v.out) { edges[outEdge].from = condensed.selfId; if(edges[outEdge].to != condensed.selfId) condensed.out.push_back(outEdge); } } for(int inEdge: nInEdges) { if(edges[inEdge].from != condensed.selfId) condensed.in.push_back(inEdge); } ufUnion(vertId, condensed.selfId); buildMst(condensed.selfId); } else { ufUnion(vertId, parent); if(ufFind(vertId) != ufFind(root)) buildMst(parent); } } void dfs(int pos, vector& seen) { if(seen[pos]) return; seen[pos] = true; for(int outEdge: vertices[pos].out) dfs(edges[outEdge].to, seen); } bool allReachable() { vector seen(vertices.size(), false); dfs(root, seen); for(size_t pos=0; pos < seen.size(); ++pos) { if(!seen[pos]) { fprintf(stderr, "NOT REACHABLE: %lu\n", pos); return false; } } return true; } int main() { int nbVert, nbEdge; scanf("%d%d%d", &nbVert, &nbEdge, &root); for(int vert=0; vert < nbVert; ++vert) vertices.push_back(Vert(vert)); for(int edgeId=0; edgeId < nbEdge; ++edgeId) { Edge edge; scanf("%d%d%d", &edge.from, &edge.to, &edge.weight); edges.push_back(edge); vertices[edge.from].out.push_back(edges.size() - 1); vertices[edge.to].in.push_back(edges.size() - 1); } if(!allReachable()) { printf("-1\n"); puts("BLEH"); return 0; } for(int vert=0; vert < nbVert; ++vert) { if(vertices[vert].suppressed || ufFind(vert) == root) continue; buildMst(vert); } printf("%d\n", cost); }