loj2587铁人两项
Posted gryzy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于loj2587铁人两项的主要内容,如果未能解决你的问题,请参考以下文章
[圆方树] Luogu P4630 Duathlon 铁人两项
模板luogu P4630Duathlon 铁人两项(圆方树)