题解:P10842 【MX-J2-T3】Piggy and Trees
arrowpoint · · 题解
这里提供一种与官方题解不同的思路。
简要题意
计算一棵树上所有路径到所有点的距离之和。
题目分析
这是一个树上统计问题,而树上统计问题的一个经典思想就是对于每个点,先计算子树中的答案,再根据题目性质将答案合并。
我们设
对于第一种情况,我们先考虑任意一条路径。设路径深度较大的端点为
我们枚举
现在考虑
对于第二种情况,我们发现路径两端点必为
对于这种情况的第一种贡献,每条路径是等价的,为
上式最坏会卡到
将所有贡献全部加起来,即为答案。时间复杂度
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 3e5+10;
const int M = 1e9+7;
int n,m,a[N];
int size[N],dis[N],pred[N]; // pred:题解中的 predis
int powsz[N]; // 题解中的 powsize
int addd[N],preadd[N]; //题解中的 add,preadd
int alld[N],ans[N]; //题解中的 alldis
vector<int> vec[N];
inline void dfs(int x,int fa){
size[x] = 1;
dis[x] = 0;
for(auto v:vec[x]){
if(v==fa) continue;
dfs(v,x);
dis[x] += dis[v]+size[v];
pred[x] += pred[v];
size[x] += size[v];
powsz[x] += size[v]*(dis[v]+size[v]);
dis[x] %= M;
pred[x] %= M;
powsz[x] %= M;
}
pred[x] += dis[x];
pred[x] %= M;
}
inline void dfs2(int x,int fa){
for(auto v:vec[x]){
if(v==fa) continue;
alld[v] = alld[x]-size[v]+(n-size[v])+M; // 从父节点开始往下推,考虑当点从父节点移到子节点时,子节点子树所有点到它距离-1,其它点距离+1
alld[v] %= M;
dfs2(v,x);
}
}
inline void dfs3(int x,int fa){
for(auto v:vec[x]){
if(v==fa) continue;
dfs3(v,x);
addd[x] += (size[v])*(dis[x]-dis[v]-size[v]+M+M)%M;
preadd[x] += preadd[v];
addd[x] %= M;
preadd[x] %= M;
}
preadd[x] += addd[x];
preadd[x] %= M;
}
inline void dfs4(int x,int fa){
int temp = 0;
for(auto v:vec[x]){
if(v==fa) continue;
dfs4(v,x);
ans[x] += ans[v];
ans[x] += (alld[x]-dis[v]-size[v]+M+M)*size[v]%M;
ans[x] += pred[v];
ans[x] += preadd[v];
ans[x] += (pred[v]*(size[x]-size[v]-1+M))%M;
ans[x] += preadd[v]*(size[x]-size[v]-1+M)%M;
temp += (alld[x]-dis[x]+M)*(size[v]*(size[x]-size[v]-1)%M)%M; // temp是真实贡献的2倍,防止出现除以二后不为整数等问题
int rest = (dis[x]-dis[v]-size[v]+M+M)%M;
temp += size[v]*((rest*(size[x]-size[v]-1+M)%M-powsz[x]+size[v]*(dis[v]+size[v])%M+M)%M)%M;
ans[x] %= M;
temp %= M;
}
temp = (temp*500000004)%M; // 注意temp是真实贡献的2倍,因此乘以2在模1e9+7意义下的逆元
ans[x] += temp;
ans[x] %= M;
}
signed main(){
ios::sync_with_stdio(false);
cin>>n;
int q1,q2;
for(int i=1;i<=n-1;i++){
cin>>q1>>q2;
vec[q1].push_back(q2);
vec[q2].push_back(q1);
}
dfs(1,0);
alld[1] = dis[1];
dfs2(1,0);
dfs3(1,0);
dfs4(1,0);
cout<<ans[1];
return 0;
}