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