Codeforces 1060E(思維+貢獻法)
阿新 • • 發佈:2018-11-20
https://codeforces.com/contest/1060/problem/E
題意
給一顆樹,在原始的圖中假如兩個點連向同一個點,這兩個點之間就可以連一條邊,定義兩點之間的長度為兩點之間的最少邊數,求加邊之後任意兩點長度之和
思路
一看到求任意兩點,知道需要用每條邊的貢獻計算(每條邊使用了多少次)
每條邊的貢獻等於邊左邊的點數*邊右邊的點數
- 然後就一直不知道怎麼解決加邊後的問題,不知道要標記哪些東西,怎麼減去
- 單獨看一條路徑,加邊之後,
- 假如邊數是偶數的話,邊數/2
- 假如邊數是奇數的話,必定會走過一條跨過二分圖的邊
所以只需要把連線二分圖的邊加上再除以2就得出答案了
#include<bits/stdc++.h> #define M 200005 #define pb push_back #define ll long long using namespace std; vector<int>g[M]; ll f[M],son[M]; int n,i,u,v; ll ans; void dfs(int u,int fa,int st){ son[u]=1;f[st]++; for(int i=0;i<g[u].size();i++){ int v=g[u][i];if(fa==v)continue; dfs(v,u,st^1); son[u]+=son[v]; } ans+=son[u]*(n-son[u]); } int main(){ cin>>n; for(i=0;i<n-1;i++){scanf("%d%d",&u,&v);g[u].pb(v);g[v].pb(u);} dfs(1,0,0); cout<<(ans+f[0]*f[1])/2; }