P5129
真是很有意思的一道题呢 虽然我交了一页才过
首先呢看到
那么既然是计算期望路径长,不能枚举每条路径,那就把路径拆开,我们来依次枚举每条边会被经过多少次。
还有为了方便,我们可以先算出总路径长再除以方案总数来算期望长度。
有了这些就可以开干了。
题上说有
- 非环边
非环边的经过次数应该很好算,次数这条边两侧的点数量之积再乘以
那么非环边对答案的贡献就是
- 环边
首先我们要明白一个道理:假如一条路径经过了环上任意一点,那么一定是存在另一条路径的。
(这也是这道题一个大坑:假设我们要从
)
那么这两条路径的长度分别是:
(假设起点是
它们一起对答案的贡献是:(由于在
而我们这里只关注环边的贡献,那么环边的贡献也就是:
环的长度
那么我们可以推测出:假设有一个起点和终点之间的路径会经过环,那么环边一定会贡献环的长度
那么我们就可以算出到底有多少种方案会经过环,再把方案数乘上这个贡献,就是环边的所有贡献了。这里呢先算有多少种方案不经过环再从总方案里扣除比较好算,而一个方案不经过环,那么起点和终点一定满足:
在同一棵子树内;
公共祖先不在环上。
说的简单明了,就是起点和终点一定要在环上的点的同一棵子树内:(如果在环上的点的两颗子树内,那么一定会经过环上的那个点)
那么,同一棵子树里的点两两之间可以产出一条不经过环的路径,那么总路径就是
那么有多少条路径不经过环也就可以算了,也就是所有子树的大小平方之和:
那么有多少条路径经过环也就可以算了,那么环边做出的总贡献也就可以算了:(
然后两种边的贡献就算完了,加起来再除以方案总数,完——
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int fi[10000001],nx[10000001],to[10000001],co[10000001],tot,length;
int n;
int loop[10000001],num,size[10000001];
int size_tree;
bool check[10000001],in[10000001],huan;
long long all;
stack<pair<int,int> >sta;
namespace Mod {
const int mod = 19260817;
int add(int x, int y) {
return (x += y) < mod ? x < 0 ? x + mod : x : x - mod;
}
int Add(int&x, int y) {
return (x += y) < mod ? x < 0 ? (x += mod) : x : (x -= mod);
}
int mul(int x, int y) {
return 1LL * x * y % mod;
}
int Mul(int&x, int y) {
return x = 1LL * x * y % mod;
}
int qpow(int x, int y) {
int res = 1;
for (; y; y >>= 1) {
if (y & 1) Mul(res, x);
Mul(x, x);
}
return res;
}
int inv(int x) {
return qpow(x, mod - 2);
}
}
using namespace Mod;
void link(int a,int b,int c)
{
nx[++tot]=fi[a];
fi[a]=tot;
to[tot]=b;
co[tot]=c;
}
void dfs1(int now,int fa,int w)
{
if(in[now])
{
length+=w;
while(sta.top().first!=now)
{
loop[++num]=sta.top().first;
length+=sta.top().second;
check[sta.top().first]=1;
sta.pop();
}
loop[++num]=now;
check[now]=1;
huan=1;
return;
}
sta.push({now,w});
in[now]=1;
for(int i=fi[now];i;i=nx[i])
{
int v=to[i];
if(v!=fa)
{
dfs1(v,now,co[i]);
if(huan)
{
return;
}
}
}
sta.pop();
}
void dfs2(int now,int fa,int w)
{
size[now]=1;
for(int i=fi[now];i;i=nx[i])
{
int v=to[i];
if(check[v]||v==fa)
{
continue;
}
dfs2(v,now,co[i]);
size[now]+=size[v];
if(check[now])
{
Add(size_tree,mul(size[v],size[v]));
}
}
Add(all,mul(w,mul(2,mul(size[now],n-size[now]))));
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int x,y,z;
cin>>x>>y>>z;
link(x,y,z);
link(y,x,z);
}
dfs1(1,0,0);
for(int i=1;i<=num;i++)
{
dfs2(loop[i],0,0);
}
Add(all,mul(mul(add(mul(n,n),-size_tree),length),inv(2)));
cout<<mul(all,inv(mul(n,n)))<<endl;
}