洛谷P4630 [APIO2018] Duathlon 铁人两项 (圆方树)

圆方树大致理解:将每个点双看做一个新建的点(方点),该点双内的所有点(圆点)都向新建的点连边,最后形成一棵树,可以给点赋予点权,用以解决相关路径问题。

在本题中,方点点权赋值为该点双的大小,因为两个点双最多有一个交点,将圆点赋为-1来去重,先用tarjan()构建出圆方树,在跑一遍dfs,dfs枚举的是作为c的点,维护sz2[ ](圆点个数,因为s和f只能是圆点),利用乘法原理累加答案即可。

注意代码中累加答案是要乘2,(s和f可以交换)。

复制代码
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=500010;
 4 typedef long long ll;
 5 
 6 struct node{
 7     int head[N],nxt[N<<1],to[N<<1],tot;
 8     void add(int u,int v){
 9         nxt[++tot]=head[u];head[u]=tot;to[tot]=v;
10         nxt[++tot]=head[v];head[v]=tot;to[tot]=u;
11     }
12 }G1,G2;
13 int dfn[N],low[N],st[N],sz[N],top,idx,tot,n,m,t1,t2,sznow;
14 //sznow存树中圆点个数 
15 void tarjan(int u){//建立圆方树 
16     sz[u]=-1;++sznow;
17     dfn[u]=low[u]=++tot;
18     st[++top]=u;//入栈 
19     for(int i=G1.head[u];i;i=G1.nxt[i]){
20         if(!dfn[G1.to[i]]){
21             tarjan(G1.to[i]);
22             low[u]=min(low[u],low[G1.to[i]]);
23             if(dfn[u]<=low[G1.to[i]]){
24                 ++idx;
25                 int v;
26                 do{
27                     v=st[top--];
28                     G2.add(v,idx);
29                     ++sz[idx];
30                 }while(v!=G1.to[i]);
31                 ++sz[idx];
32                 G2.add(u,idx);
33                 //将该点双看做一个点,内部的点向该点连边 
34             }
35         }
36         else low[u]=min(low[u],dfn[G1.to[i]]);
37     }
38 }
39 
40 ll ans;
41 int sz2[N];
42 
43 void dfs(int u,int fa){
44     sz2[u]=u<=n;    //只有圆点才可作为s或f,c在圆点方点都行
45     for(int i=G2.head[u],v;i;i=G2.nxt[i]){
46         if((v=G2.to[i])!=fa){//计算子树两两积 
47             dfs(v,u);
48             ans+=2ll*sz2[u]*sz2[v]*sz[u];
49             sz2[u]+=sz2[v];
50         }
51     }
52     ans+=2ll*sz2[u]*(sznow-sz2[u])*sz[u];
53 }
54 
55 int main(){
56     scanf("%d%d",&n,&m);
57     idx=n;
58     for(int i=1;i<=m;i++){
59         scanf("%d%d",&t1,&t2);
60         G1.add(t1,t2);
61     }
62     for(int i=1;i<=n;i++){
63         if(!dfn[i]){//对于每个连通块都要先清空 
64             sznow=0;
65             top=0;
66             tarjan(i);
67             dfs(i,0);
68         }
69     }
70     printf("%lld\n",ans);
71 }
复制代码

 



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   YHXo  阅读(37)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示