Codeforces 1060E(思维+贡献法)

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;
}

猜你喜欢

转载自www.cnblogs.com/VIrtu0s0/p/9986780.html
今日推荐