structEdge { int from, to, nxt; } edge[N], edge2[N]; int tot; int head[N]; voidadd_edge(int u, int v) { edge[++tot].to = v; edge[tot].from = u; edge[tot].nxt = head[u]; head[u] = tot; } int tot2; int head2[N]; int in[N]; voidadd_edge2(int u, int v) { edge2[++tot2].to = v; edge2[tot2].from = u; edge2[tot2].nxt = head2[u]; head2[u] = tot2; in[v]++; } int val[N]; //点权
int dfn[N], low[N]; //dfs序记录、追溯到的最早的栈中节点的次序号 int dfntot; //dfs序 int st[N]; //栈 bool in_stack[N]; //是否入栈 int tp; //栈顶指针 int scc[N], sc; // 结点 i 所在 scc 的编号 int sz[N]; // 强连通 i 的大小 int scval[N]; voidtarjan(int u) { low[u] = dfn[u] = ++dfntot; //记录dfs序 st[++tp] = u, in_stack[u] = 1; //当前点入栈,并标记已入栈 for (int i = head[u]; i; i = edge[i].nxt) { constint &v = edge[i].to; if (!dfn[v]) //没有访问过 { tarjan(v); //递归访问 low[u] = min(low[u], low[v]); //更新与u相连的连通图第一次访问的dfs序 } elseif (in_stack[v]) //成环 low[u] = min(low[u], dfn[v]); //更新第一次访问的dfs序 } if (dfn[u] == low[u]) //找到强连通分量 { ++sc; while (st[tp] != u) //将环中的节点出栈并记录 { scc[st[tp]] = sc; sz[sc]++; scval[sc] += val[st[tp]]; //强连通分量的权值 in_stack[st[tp]] = 0; --tp; } scc[st[tp]] = sc; //上一次入栈的当前节点 sz[sc]++; scval[sc] += val[st[tp]]; in_stack[st[tp]] = 0; //出栈 --tp; } } voidrebuild()//缩点重构图 { for (int i = 1; i <= m; i++) { int scx = scc[edge[i].from], scy = scc[edge[i].to]; if (scx == scy) continue; //强连通分量缩点了 add_edge2(scx, scy); } }