1060E Sergey and Subway(思维题,dfs)

题意:给出一颗树,现在,给哪些距离为2的点对,加上一条边,问所有点对的距离和

题解:如果没有加入新的边,距离和就会等于每条边的贡献,由于是树,我们用点来代表点上面的边,对于每条边,它的贡献将是(子树大小)*(n-子树大小)

而这题加上了新边,我们依然这样算贡献,跨越旧边的次数,依然是(子树大小)*(n-子树大小),只不过都是两个两个的走,那么虽然跨越了这条边,但是它可能走的是新边,也就是他的贡献要除以2,对于那些真正跨越了旧边的点对,它其实不需要除2的,所以我们要把它加上,这些点对的数量是(奇数层点数*偶数层点数)

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e5+10;
ll f[maxn],nex[2*maxn],to[2*maxn],cnt=0,vis[maxn],siz[maxn],num[3];
void add(int a,int b)
{
    cnt++;
    to[cnt]=b;
    nex[cnt]=f[a];
    f[a]=cnt;
}
int dfs(int x,int le)
{
    siz[x]=1;
    vis[x]=1;
    num[le%2]++;
    for(int i=f[x];i;i=nex[i])
    {
        int v=to[i];
        if(vis[v]==0)
        {
            dfs(v,le+1);
            siz[x]+=siz[v];
        }
    }
    return siz[x];
}
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n-1;i++)
    {
        int a,b;
        scanf("%d %d",&a,&b);
        add(a,b);
        add(b,a);
    }
    dfs(1,1);
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        ans+=siz[i]*(n-siz[i]);
    }
    ans+=num[0]*num[1];
    cout<<ans/2<<endl;
	return 0;
}

依然看不懂请参考:https://blog.csdn.net/qq_37555704/article/details/82948958?utm_source=blogxgwz2

posted @ 2018-10-18 18:56  czh~  阅读(153)  评论(0编辑  收藏  举报