1. 程式人生 > >解題:APIO 2018 鐵人兩項

解題:APIO 2018 鐵人兩項

aps pla vector 建立 lap %d 圓點 esp spa

題面

建立圓方樹,考慮所有路徑,發現路徑上原來的點雙(現在的方點)裏的點都可以做中間點。但是路徑上被方點夾著的圓點被計重了,要扣掉;枚舉的兩個端點也被算進去了,要扣掉。所以直接將方點權值設為點雙大小,圓點權值設為-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

解題:APIO 2018 鐵人兩項