博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LOJ#2587[APIO2018]Duathlon铁人两项(圆方树)
阅读量:5071 次
发布时间:2019-06-12

本文共 2569 字,大约阅读时间需要 8 分钟。

题目链接

前置知识

圆方树

解析

考虑一条从\(s\)\(f\)的路径产生的贡献是除\(s, f\)外经过的点数

如果这条路径经过了某个点双连通分量,点双上的每个点都会产生贡献

点双\(\rightarrow\)圆方树

建出圆方树,方点权值为代表的点双的大小

这样两点间的路径对应成两个圆点间的路径,由于一条路径会经过\(s\)\(f\)自己所在的点双,而\(c\)不能在\(s\)\(f\),所以每个圆点权值为\(-1\)

于是一对\(s, f\)的贡献就是圆方树上的路径上的点权和

考虑每个点被多少条路径经过,乘上点权就是这个点对答案的贡献

于是就变成了一个简单的树上路径统计问题

因为交换\(s\)\(f\)算不同的方案,最后答案乘\(2\)

代码

自带大常数……洛谷\(1000ms\)\(LOJ \ 5600ms\)……

#include 
#include
#include
#include
#define MAXN 100005#define MAXM 200005typedef long long LL;struct Graph { struct Edge { int v, next; Edge(int _v = 0, int _n = 0):v(_v), next(_n) {} } edge[MAXM << 1]; int head[MAXN << 1], cnt; void init() { memset(head, -1, sizeof head); cnt = 0; } void add_edge(int u, int v) { edge[cnt] = Edge(v, head[u]); head[u] = cnt++; } void insert(int u, int v) { add_edge(u, v); add_edge(v, u); }};void Tarjan(int, int);void dfs(int, int);int N, M, dfn[MAXN], low[MAXN], idx, tot;int stk[MAXN], top;int size[MAXN << 1], w[MAXN << 1], root[MAXN << 1];bool vis[MAXN << 1];LL ans;Graph G, T;int main() { scanf("%d%d", &N, &M); tot = N; G.init(); T.init(); for (int i = 0; i < M; ++i) { int u, v; scanf("%d%d", &u, &v); G.insert(u, v); } for (int i = 1; i <= N; ++i) { w[i] = -1, size[i] = 1; if (!dfn[i]) Tarjan(i, 0); } for (int i = 1; i <= tot; ++i) if (!vis[i]) { root[i] = i; dfs(i, 0); } for (int i = 1; i <= tot; ++i) ans += (LL)(size[root[i]] - size[i]) * size[i] * w[i]; printf("%lld\n", ans << 1); return 0;}void Tarjan(int u, int fa) { dfn[u] = low[u] = ++idx; for (int i = G.head[u]; ~i; i = G.edge[i].next) { int v = G.edge[i].v; if (v == fa) continue; if (!dfn[v]) { stk[top++] = v; Tarjan(v, u); low[u] = std::min(low[u], low[v]); if (low[v] >= dfn[u]) { int p; ++tot; do { p = stk[--top]; T.insert(tot, p); ++w[tot]; } while(p ^ v); T.insert(tot, u); ++w[tot]; } } else low[u] = std::min(low[u], dfn[v]); }}void dfs(int u, int fa) { vis[u] = 1; for (int i = T.head[u]; ~i; i = T.edge[i].next) { int v = T.edge[i].v; if (v == fa) continue; root[v] = root[u], dfs(v, u); ans += (LL)size[v] * size[u] * w[u]; size[u] += size[v]; }}//Rhein_E

转载于:https://www.cnblogs.com/Rhein-E/p/10613321.html

你可能感兴趣的文章
常见错误收集: lucene 读取word文档问题
查看>>
关于可空类型?
查看>>
LINUX命令和文件夹结构
查看>>
[debug]调试Release版本应用程序
查看>>
Validation Rule和Binding Group
查看>>
不管在哪里工作,请记住这些话
查看>>
HDU 5441 Travel
查看>>
上传文件没有写权限Access to the path is denied
查看>>
Docker到底是什么
查看>>
Android常用逆向工具+单机游戏破解
查看>>
《像计算机科学家一样思考Python》-递归
查看>>
codevs2171 棋盘覆盖
查看>>
SQL Server ->> 生成Numbers辅助表
查看>>
HDU1569+最大点权集
查看>>
(网络收集)彻底解决超链接提交中文乱码问题
查看>>
JS-隐士类型转换‘1’+1、‘1’-1、++‘1’为什么不一样?
查看>>
spark(03)
查看>>
基础教程
查看>>
外观模式
查看>>
shell 父子shell 调用
查看>>