loj2587铁人两项

无向图,图中选出定点三元组(a,b,c),a->b->c的路径没有重复边。问方案有多少?

————————————————————————————————————————————

首先求出圆方树,方点权值为连接的圆点数量,圆点权值为-1

这时,枚举a,c点,b点的方案数为a,c路径上的点权和。

枚举a,c点然后计算点权和明显超时。于是我们枚举b点,计算通过它的方案数。

所以神搜后有三种可能,b点的各个子分支与其它点,b点的向上分支与其它点,如果b点为a或c点的情况

————————————————————————————————————————————

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int maxn = 2e5 + 10, maxm = 8e5 + 10;
 4 int n, m, cnt;
 5 struct edge {
 6     int u, v, nxt;
 7 } e[maxm], ee[maxm];
 8 int head[maxn], js, headd[maxn], jss;
 9 void addage(int u, int v) {
10     e[++js].u = u;
11     e[js].v = v;
12     e[js].nxt = head[u];
13     head[u] = js;
14 }
15 void addagee(int u, int v) {
16     ee[++jss].u = u;
17     ee[jss].v = v;
18     ee[jss].nxt = headd[u];
19     headd[u] = jss;
20 }
21 int dfn[maxn], low[maxn], tim, sta[maxn], top, pw[maxn];
22 int sum, siz[maxn];
23 bool vis[maxn];
24 void tarjan(int u, int fa) {
25     dfn[u] = low[u] = ++tim;
26     sta[++top] = u;
27     for (int i = head[u]; i; i = e[i].nxt) {
28         int v = e[i].v;
29         if (!dfn[v]) {
30             tarjan(v, u);
31             low[u] = min(low[v], low[u]);
32             if (low[v] >= dfn[u]) {
33                 cnt++;
34                 int tp = 0;
35                 while (tp != v) {
36                     tp = sta[top--];
37                     addagee(cnt, tp);
38                     addagee(tp, cnt);
39                     pw[cnt]++;
40                     pw[tp] = -1;
41                 }
42                 addagee(cnt, u);
43                 addagee(u, cnt);
44                 pw[cnt]++;
45                 pw[u] = -1;
46             }
47         } else if (v != fa)
48             low[u] = min(low[u], dfn[v]);
49     }
50 }
51 long long ans;
52 void dfs1(int u, int fa) {
53     vis[u] = 1;
54     siz[u] = (u <= n);
55     for (int i = headd[u]; i; i = ee[i].nxt) {
56         int v = ee[i].v;
57         if (v == fa)
58             continue;
59         dfs1(v, u);
60         siz[u] += siz[v];
61     }
62 }
63 void dfs2(int u, int fa) {
64     for (int i = headd[u]; i; i = ee[i].nxt) {
65         int v = ee[i].v;
66         if (v == fa)
67             continue;
68         dfs2(v, u);
69         ans += (long long)pw[u] * (sum - siz[v]) * siz[v];  // u的每一个子分支与其它点的
70     }
71     ans += (long long)pw[u] * (sum - siz[u]) * siz[u];  // u向上的分支与其它的点
72     if (u <= n)
73         ans += (long long)pw[u] * (sum - 1);  // u作为端点
74 }
75 int main() {
76     scanf("%d%d", &n, &m);
77     for (int u, v, i = 0; i < m; ++i) {
78         scanf("%d%d", &u, &v);
79         addage(u, v);
80         addage(v, u);
81     }
82     cnt = n;
83     for (int i = 1; i <= n; ++i)
84         if (!dfn[i])
85             tarjan(i, 0);
86     for (int i = 1; i <= n; ++i)
87         if (!vis[i]) {
88             dfs1(i, 0);
89             sum = siz[i];
90             dfs2(i, 0);
91         }
92     cout << ans;
93 
94     return 0;
95 }
View Code
原文地址:https://www.cnblogs.com/gryzy/p/13140808.html