[APIO2018] Duathlon 铁人两项
给定一张简单无向图,问有多少对三元组 ( 互不相同)使得存在一条简单路径从 出发,经过 到达 。
很显然先建出圆方树,然后考虑 存在的数量
我的一般想法是考虑固定 统计 的数量
这确实用了树的性质,但没用到圆方树的性质,而且因为点双的讨论,使统计非常复杂
后来看了看正解,颇有一种如获至宝的感觉
考虑固定 统计 的数量,那就是 到 所有简单路径点的并集大小 (即除去 )
貌似也并不好弄,然而放到圆方树上就成了路径上圆点和方点所连的圆点的个数
于是不难想到将方点权值赋为与其相连圆点个数,圆点权值赋为
到 所有简单路径点的并集大小即为路径上的点权和
统计的话,换种思考角度,变为统计一个点的点权的贡献,这就很简单了
#include <cstdio> #include <iostream> #define RE register #define IN inline using namespace std; typedef long long LL; const int N = 2e5 + 5; int n, m, cnt, top, tot1, tot2, dfc; int val[N], h1[N], h2[N], low[N], dfn[N], siz[N], stk[N]; LL ans; struct edge{int to, nxt;}e1[N * 5], e2[N * 5]; IN void add1(int x, int y){e1[++tot1] = edge{y, h1[x]}, h1[x] = tot1;} IN void add2(int x, int y){e2[++tot2] = edge{y, h2[x]}, h2[x] = tot2;} void Tarjan(int x) { dfn[x] = low[x] = ++dfc, stk[++top] = x, val[x] = -1; for(RE int i = h1[x]; i; i = e1[i].nxt) { int v = e1[i].to; if (!dfn[v]) { Tarjan(v), low[x] = min(low[x], low[v]); if (dfn[x] == low[v]) { ++cnt, add2(cnt, x), add2(x, cnt), ++val[cnt]; for(RE int u = 0; u ^ v; --top) u = stk[top], add2(cnt, u), add2(u, cnt), ++val[cnt]; } } else low[x] = min(low[x], dfn[v]); } } void Dfs(int x, int fa) { siz[x] = (x <= n); for(RE int i = h2[x]; i; i = e2[i].nxt) { int v = e2[i].to; if (v == fa) continue; Dfs(v, x), ans += 2LL * val[x] * siz[v] * siz[x], siz[x] += siz[v]; } ans += 2LL * val[x] * siz[x] * (dfc - siz[x]); } int main() { scanf("%d%d", &n, &m); for(RE int i = 1, x, y; i <= m; i++) scanf("%d%d", &x, &y), add1(x, y), add1(y, x); cnt = n; for(RE int rt = 1; rt <= n; rt++) if (!dfn[rt]) top = dfc = 0, Tarjan(rt), Dfs(rt, 0); printf("%lld\n", ans); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】