解题:APIO 2018 铁人两项

题面

建立圆方树,考虑所有路径,发现路径上原来的点双(现在的方点)里的点都可以做中间点。但是路径上被方点夹着的圆点被计重了,要扣掉;枚举的两个端点也被算进去了,要扣掉。所以直接将方点权值设为点双大小,圆点权值设为-1,所有圆点间路径权值和的和即为答案

注意图可能不连通,草(汉语)

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=200005,M=400005;
 7 int n,m,r,c,t1,t2,cnt,Cnt,tot,top; long long sum,ans;
 8 int dfn[N],low[N],col[N],isc[N],stk[N],siz[N],dis[N];
 9 int p[N],noww[M],goal[M],P[N],Noww[M],Goal[M],val[N];
10 vector<int> ve[N]; 
11 void Link(int f,int t)
12 {
13     noww[++cnt]=p[f];
14     goal[cnt]=t,p[f]=cnt;
15     noww[++cnt]=p[t];
16     goal[cnt]=f,p[t]=cnt;
17 }
18 void Linka(int f,int t)
19 { 
20     Noww[++Cnt]=P[f];
21     Goal[Cnt]=t,P[f]=Cnt;
22     Noww[++Cnt]=P[t];
23     Goal[Cnt]=f,P[t]=Cnt;
24 }
25 void Tarjan_PBC(int nde)
26 { 
27     int tep=0; stk[++top]=nde;
28     dfn[nde]=low[nde]=++tot;
29     for(int i=p[nde];i;i=noww[i])
30         if(!dfn[goal[i]])
31         {
32             Tarjan_PBC(goal[i]);
33             low[nde]=min(low[nde],low[goal[i]]);
34             if(dfn[nde]<=low[goal[i]])
35             {
36                 if(nde!=r||++tep>1) isc[nde]=true;
37                 int tmp; c++;
38                 do
39                 {
40                     tmp=stk[top--],col[tmp]=c;
41                     ve[c].push_back(tmp);
42                 }while(tmp!=goal[i]);
43                 ve[c].push_back(nde);
44             }
45         }
46         else low[nde]=min(low[nde],dfn[goal[i]]);
47 }
48 void DFS(int nde,int fth)
49 {
50     if(nde<=n) siz[nde]=1;
51     for(int i=P[nde];i;i=Noww[i])
52         if(Goal[i]!=fth) DFS(Goal[i],nde),siz[nde]+=siz[Goal[i]];
53 }
54 void Getans(int nde,int fth)
55 {
56     long long tmp=0;
57     int sizz=tot-siz[nde];
58     for(int i=P[nde];i;i=Noww[i])
59         if(Goal[i]!=fth) 
60         {
61             int G=Goal[i],S=siz[G];
62             tmp+=1ll*sizz*S,sizz+=S;
63             Getans(Goal[i],nde);
64         }
65     if(nde<=n) ans-=(tmp+tot-1)*2;
66     else ans+=2*tmp*val[nde];
67 }
68 int main()
69 {
70     scanf("%d%d",&n,&m);
71     for(int i=1;i<=m;i++)
72         scanf("%d%d",&t1,&t2),Link(t1,t2);
73     for(int i=1;i<=n;val[i]=-1,i++)
74         if(!dfn[i]) r=i,Tarjan_PBC(i);
75     for(int i=1;i<=c;i++)
76     {
77         val[n+i]=ve[i].size();
78         for(int j=0;j<val[n+i];j++) 
79             Linka(n+i,ve[i][j]);
80     }
81     for(int i=1;i<=n;i++)
82         if(!siz[i]) DFS(i,0),tot=siz[i],Getans(i,0);
83     printf("%lld",ans);
84     return 0;
85 }
View Code

猜你喜欢

转载自www.cnblogs.com/ydnhaha/p/10392496.html