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 ...
随机推荐
- Vue实现在前端导出Excel 方法1
也可以去看我的方法2:https://www.cnblogs.com/yingyigongzi/p/10915403.html ------------------------------------ ...
- (三)air202连接阿里云上传静态数据
具体步骤跳转–合宙官网 air202luat二次开发设备接入阿里云(一) air202luat二次开发设备接入阿里云(二) air202luat二次开发设备接入阿里云(三) 可能遇到的问题 群文件中有 ...
- 学习Java的9张思维导图
转自:https://blog.csdn.net/aitaozi11/article/details/79652943 网上搜集了java的学习思维导图,分享给大家. 01.Java程序设计(基础) ...
- Linux centos 安装 mysql 5.7
一.mysql下载 1.方式一(简单粗暴) 直接在linux 目录下:wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.25-l ...
- spring AOP事务
1 <bean id="tttt" class="com.ry.project.dataSouces.UserLogger"/> 2 <aop ...
- for in和for of的简单区别
//for in可以遍历数组和对象,但是for of只能遍历数组,不可以遍历对象 var arr = [1,4,5,6,7,8]; var obj = { name:'za', age:19, say ...
- WAMP 2.5 无法访问局域网的解决方法
打开Apache配置文件 httpd.conf (该文件在wamp\bin\apache\apache2.4.9\conf) DocumentRoot "d:/wamp/www/" ...
- .NetCore 项目在服务器打包失败解决
错误描述:NuGet警告 NU3037 NU3028 原因:Nuget无法访问到json所在的网络 2021年1月31日更新:更好的方法 把自动生成的Dockerfile内的AS build 替换成官 ...
- JS_DOM操作之绑定事件
1 - 静态绑定:直接把事件写在标签元素中 <div id="div" onclick="foo(this)">click</div> ...
- UNION / UNION ALL 区别
Union:对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序: Union All:对两个结果集进行并集操作,包括重复行,不进行排序: 使用union all: select top 5 ...