洛谷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 @ 2022-06-10 19:09  YHXo  阅读(52)  评论(0)    收藏  举报