P4630-[APIO2018]Duathlon铁人两项【圆方树】
正题
题目链接:https://www.luogu.com.cn/problem/P4630
题目大意
\(n\)个点\(m\)条边的一张无向图,求有多少对三元组\((s,c,f)\)满足\(s\neq f\neq t\)且存在一条从\(s\)到\(f\)的简单路径经过\(c\)
解题思路
一个比较显然的结论是在一个点双中的三个点\((a,b,c)\)那么必然存在一条\(a\)到\(b\)的简单路径经过\(c\)。因为一定存在两条不交的\(a->c\)和\(c->b\)的路径,那么如果一条\(a->c\)和\(c->b\)的路径交了,那么另一条就一定不交。
然后从一个点双出来后就不能再回到这个点双了,所以我们可以考虑在圆方树上做这个问题。
设定义圆点的权值为\(-1\),方点的权值为连接的圆点数量,这样我们在圆方树上走的时候就可以固定经过进入和离开这个点双的点了。
然后问题就变为了求每条圆点之间路径的点权和的和。
用树形\(dp\)搞就好了,时间复杂度\(O(n)\)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
const int N=2e5+10;
int n,m,num,cnt,dfc,w[N];
int low[N],dfn[N],siz[N];
vector<int> G[N],T[N];
stack<int> s;
long long ans;
void tarjan(int x){
dfn[x]=low[x]=++dfc;
w[x]=-1;s.push(x);num++;
for(int y:T[x])
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
if(dfn[x]==low[y]){
++cnt;int k;
do{
k=s.top();
G[cnt].push_back(k);
G[k].push_back(cnt);
w[cnt]++;s.pop();
}while(k!=y);
G[cnt].push_back(x);
G[x].push_back(cnt);
w[cnt]++;
}
}
else low[x]=min(low[x],dfn[y]);
return;
}
void solve(int x,int fa){
siz[x]=(x<=n);
for(int y:G[x]){
if(y==fa)continue;
solve(y,x);
ans+=2ll*siz[y]*siz[x]*w[x];
siz[x]+=siz[y];
}
ans+=2ll*siz[x]*(num-siz[x])*w[x];
return;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
T[x].push_back(y);
T[y].push_back(x);
}
cnt=n;
for(int i=1;i<=n;i++)
if(!dfn[i]){
num=0;
tarjan(i);
solve(i,0);
}
printf("%lld\n",ans);
return 0;
}
P4630-[APIO2018]Duathlon铁人两项【圆方树】的更多相关文章
- [APIO2018] Duathlon 铁人两项 圆方树,DP
[APIO2018] Duathlon 铁人两项 LG传送门 圆方树+简单DP. 不会圆方树的话可以看看我的另一篇文章. 考虑暴力怎么写,枚举两个点,答案加上两个点之间的点的个数. 看到题面中的一句话 ...
- 【Luogu4630】【APIO2018】 Duathlon 铁人两项 (圆方树)
Description 给你一张\(~n~\)个点\(~m~\)条边的无向图,求有多少个三元组\(~(x, ~y, ~z)~\)满足存在一条从\(~x~\)到\(~z~\)并且经过\(~y~\)的 ...
- LOJ 2587 「APIO2018」铁人两项——圆方树
题目:https://loj.ac/problem/2587 先写了 47 分暴力. 对于 n<=50 的部分, n3 枚举三个点,把图的圆方树建出来,合法条件是 c 是 s -> f 路 ...
- loj2587 「APIO2018」铁人两项[圆方树+树形DP]
主要卡在一个结论上..关于点双有一个常用结论,也经常作为在圆方树/简单路径上的良好性质,对于任意点双内互不相同的三点$s,c,t$,都存在简单路径$s\to c\to t$,证明不会.可以参见clz博 ...
- 洛谷P4630 [APIO2018] Duathlon 铁人两项 【圆方树】
题目链接 洛谷P4630 题解 看了一下部分分,觉得树的部分很可做,就相当于求一个点对路径长之和的东西,考虑一下能不能转化到一般图来? 一般图要转为树,就使用圆方树呗 思考一下发现,两点之间经过的点双 ...
- 洛谷P4630 [APIO2018] Duathlon 铁人两项 (圆方树)
圆方树大致理解:将每个点双看做一个新建的点(方点),该点双内的所有点(圆点)都向新建的点连边,最后形成一棵树,可以给点赋予点权,用以解决相关路径问题. 在本题中,方点点权赋值为该点双的大小,因为两个点 ...
- [APIO2018]铁人两项 --- 圆方树
[APIO2018] 铁人两项 题目大意: 给定一张图,问有多少三元组(a,b,c)(a,b,c 互不相等)满足存在一条点不重复的以a为起点,经过b,终点为c的路径 如果你不会圆方树 ------- ...
- [APIO2018]铁人两项——圆方树+树形DP
题目链接: [APIO2018]铁人两项 对于点双连通分量有一个性质:在同一个点双里的三个点$a,b,c$,一定存在一条从$a$到$c$的路径经过$b$且经过的点只被经过一次. 那么我们建出原图的圆方 ...
- [APIO2018]铁人两项 [圆方树模板]
把这个图缩成圆方树,把方点的权值设成-1,圆点的权值设成点双的size,算 经过这个点的路径的数量*这个点的点权 的和即是答案. #include <iostream> #include ...
- 洛谷P4630 铁人两项--圆方树
一道很好的圆方树入门题 感谢PinkRabbit巨佬的博客,讲的太好啦 首先是构建圆方树的代码,也比较好想好记 void tarjan(int u) { dfn[u] = low[u] = ++dfn ...
随机推荐
- 定时执行的任务Quartz.net
- 【mysql】用户和权限管理
1.用户管理 相关命令如下 命令 描述 备注 create user zhang3 identified by '123123'; 创建名称为zhang3 的用户,密码设为123123: sele ...
- 七:使用Session进行会话管理
一.Session简单介绍 在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下).因此,在需要保存用户数据时,服务 ...
- 彻底搞懂volatile关键字
对于volatile这个关键字,相信很多朋友都听说过,甚至使用过,这个关键字虽然字面上理解起来比较简单,但是要用好起来却不是一件容易的事.这篇文章将从多个方面来讲解volatile,让你对它更加理解. ...
- 理解ASP.NET Core - [02] Middleware
注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 中间件 先借用微软官方文档的一张图: 可以看到,中间件实际上是一种配置在HTTP请求管道中,用 ...
- TypeScript 中枚举类型的理解?应用场景?
一.是什么 枚举是一个被命名的整型常数的集合,用于声明一组命名的常数,当一个变量有几种可能的取值时,可以将它定义为枚举类型 通俗来说,枚举就是一个对象的所有可能取值的集合 在日常生活中也很常见,例如表 ...
- 二、grep文本搜索工具
grep命令作为Unix中用于文本搜索的神奇工具,能够接受正则表达式,生成各种格式的输出.除此外,它还有大量有趣的选项. # 搜索包含特定模式的文本行: [root@centos8 ~]#grep p ...
- Hounter
这题是概率与期望,不是很熟,所以冲了两篇题解才来写总结. 首先可以发现1猎人死的轮数是他之前死了的列人数加一. 那么题目转化为求先于一号猎人死的猎人数的期望值. 考虑这样一个事情,就是 ...
- Easy-ARM IMX283 移植RTL8192CU驱动
测试平台 宿主机平台:Ubuntu 12.04.4 LTS 目标机:Easy-ARM IMX283 目标机内核:Linux 2.6.35.3 无线网卡驱动下载地址:http://www.comfast ...
- TreeView和ListView数据库查询数据联动操作
好久不用了,重新整理下放这里以备需要使用,功能见图 数据库表结构 定义TreeView addObject中data存储的记录集 type PNode = ^TNode; TNode = record ...