[洛谷P4630][APIO2018] Duathlon 铁人两项
题目大意:给一张无向图,求三元组$(u,v,w)$满足$u->v->w$为简单路径,求个数
题解:圆方树,缩点后$DP$,因为同一个点双中的点一定地位相同
卡点:1.$father$数组开小,一不小心就续到了下面的$bool$的$vis$数组中,然后就挂成$98$,因为发现去掉没用的$vis$数组变成$86$,才找到问题
C++ Code:
#include <cstdio> #include <cstring> #define maxn 100010 #define maxm 200010 #define N 200010 #define ONLINE_JUDGE #define read() R::READ() #include <cctype> namespace R { int x; #ifdef ONLINE_JUDGE char *ch, op[1 << 28]; inline void init() { fread(ch = op, 1, 1 << 28, stdin); } inline int READ() { while (isspace(*ch)) ch++; for (x = *ch & 15, ch++; isdigit(*ch); ch++) x = x * 10 + (*ch & 15); return x; } #else char ch; inline int READ() { ch = getchar(); while (isspace(ch)) ch = getchar(); for (x = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) x = x * 10 + (ch & 15); return x; } #endif } int n, m; long long ans; inline int min(int a, int b) {return a < b ? a : b;} namespace Tree { int CNT; int head[N], cnt; struct Edge { int to, nxt; } e[N << 1]; void add(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt; } long long w[N], f[N], sz[N], pointsz; int fa[N]; void dfs(int u) { sz[u] = bool(u <= n); long long tmp = 0; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v != fa[u]) { fa[v] = u; dfs(v); tmp += sz[v] * sz[u]; sz[u] += sz[v]; } } tmp += sz[u] * (pointsz - sz[u]); ans += w[u] * tmp << 1ll; } } namespace Graph { int head[maxn], cnt; struct Edge { int to, nxt; } e[maxm << 1]; void add(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; e[++cnt] = (Edge) {a, head[b]}; head[b] = cnt; } int DFN[maxn], low[maxn], idx, fa[maxn]; int S[maxn], top; void Tarjan(int u) { Tree::pointsz++; DFN[u] = low[u] = ++idx; Tree::w[S[++top] = u] = -1; int v; for (int i = head[u]; i; i = e[i].nxt) { v = e[i].to; if (!DFN[v]) { fa[v] = u; Tarjan(v); low[u] = min(low[u], low[v]); if (low[v] >= DFN[u]) { Tree::w[++Tree::CNT] = 1; Tree::add(Tree::CNT, u); do { v = S[top--]; Tree::add(Tree::CNT, v); Tree::w[Tree::CNT]++; } while (v != e[i].to); } } else low[u] = min(low[u], DFN[v]); } } inline void tarjan(int n) { for (int i = 1; i <= n; i++) if (!DFN[i]) { Tree::pointsz = 0; Tarjan(i); Tree::dfs(i); } } } int main() { #ifdef ONLINE_JUDGE R::init(); #endif Tree::CNT = n = read(), m = read(); for (int i = 1; i <= m; i++) Graph::add(read(), read()); Graph::tarjan(n); printf("%lld\n", ans); return 0; }