传送门:bzoj2878
讨论比较繁琐:
先求出每个点向下走的期望 g i g_i gi,再求出向上走的期望 f i f_i fi。设 i i i的儿子集合为 s o n i son_i soni, d i s i , j dis_{i,j} disi,j表示 i , j i,j i,j之间的距离, f a i fa_i fai表示 i i i的父亲结点, d i d_i di表示 i i i的度数。
树:
g i = 1 ∣ s o n i ∣ ∑ j ∈ s o n i ( g j + d i s i , j ) g_i=\dfrac{1}{|son_i|}\sum\limits_{j\in son_i}(g_j+dis_{i,j}) gi=∣soni∣1j∈soni∑(gj+disi,j)
f i = ( g f i × ∣ s o n f i ∣ − g i − d i s f a i , i + f f i d f a i − 1 ) + d i s f a i , i f_i=(\dfrac{g_{f_i}\times|son_{f_i}|-g_i-dis_{fa_i,i}+f_{f_i}}{d_{fa_i}-1})+dis_{fa_i,i} fi=(dfai−1gfi×∣sonfi∣−gi−disfai,i+ffi)+disfai,i
每个点的期望: g i × ∣ s o n i ∣ + f i d i \dfrac{g_i\times|son_i|+f_i}{d_i} digi×∣soni∣+fi
基环树:
设缩点后的环为根,先不考虑环边求出所有点的 g g g值。
因为环点 ≤ 20 \leq 20 ≤20,考虑分别 n 2 n^2 n2枚举每个点顺时针和逆时针向上走的期望,概率都为 0.5 0.5 0.5。
设起点为 x x x,下一个点为 t o x to_x tox,则:
f x = d t o x − 2 d t o x − 1 × g t o x + 1 d t o x − 1 f t o x + d i s f x , x f_x=\dfrac{d_{to_x}-2}{d_{to_x}-1}\times g_{to_x}+\dfrac{1}{d_{to_x}-1}f_{to_x}+dis_{f_x,x} fx=dtox−1dtox−2×gtox+dtox−11ftox+disfx,x
因为在环上,所以如果一直沿着环走迭代到 x x x前一个点 f r x fr_x frx时, f f r x = 0 f_{fr_x}=0 ffrx=0,倒着退回去就可以了。
求出环上的 f i f_i fi之后再带回子树即可。
p.s. 注意讨论分母为0的情况。
#include
using namespace std;
typedef double db;
const int N=1e5+100;
int n,m,d[N];
int head[N],to[N<<1],nxt[N<<1],w[N<<1],tot;
db f[N],g[N],ans;
char cp;
inline void rd(int &x)
{
cp=getchar();x=0;
for(;!isdigit(cp);cp=getchar());
for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
}
inline void lk(int u,int v,int cc)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=cc;}
namespace tree{
void gtdn(int x,int fr)
{
int sn=(d[x]-(x!=1));if(!sn) return;
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==fr) continue;
gtdn(j,x);g[x]+=(g[j]+w[i]);
}
g[x]/=(db)sn;
}
void gtup(int x,int fr)
{
int sn=d[x]-(x!=1),j,i;db bs=f[x]+g[x]*sn;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==fr) continue;
f[j]=(db)w[i];
if(d[x]>1) f[j]+=(bs-g[j]-w[i])/(db)(d[x]-1);
gtup(j,x);
}
}
inline void sol()
{
int i,x,y,z;
for(i=1;i<n;++i){
rd(x);rd(y);rd(z);d[x]++;d[y]++;
lk(x,y,z);lk(y,x,z);
}
gtdn(1,0);gtup(1,0);
for(i=1;i<=n;++i) ans+=((d[i]-(i!=1))*g[i]+f[i])/(db)d[i];
ans/=(db)n;
}
}
namespace Basc{
#define trs(x) (x>cnt)?(x-cnt):x
db sup[N],nup[N];
int st,ed,lca,dep[N],fa[N],fr[N],dir[N];
int h[N],cnt,len[22][22];
bool cir[N];
int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);}
void dfs(int x)
{
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==fr[x]) continue;
fr[j]=x;dep[j]=dep[x]+1;dfs(j);
}
}
void gtdn(int x)
{
int sn=(d[x]-1-(cir[x]?1:0));if(!sn) return;
for(int j,i=head[x];i;i=nxt[i]){
j=to[i];if(j==fr[x] || cir[j]) continue;
fr[j]=x;gtdn(j);g[x]+=(g[j]+w[i]);
}
g[x]/=(db)sn;
}
void gtup(int x)
{
int sn,j,i;db bs;
if(cir[x]){sn=d[x]-2;bs=f[x]*2+g[x]*sn;}
else{sn=d[x]-1;bs=f[x]+g[x]*sn;}
if(!sn) return;
for(i=head[x];i;i=nxt[i]){
j=to[i];if(j==fr[x] || cir[j]) continue;
f[j]=w[i]+(bs-g[j]-w[i])/(db)(d[x]-1);
gtup(j);
}
}
inline void sol()
{
int i,j,k,x,y,z,ix,iy,nt,vl;
for(i=1;i<=n;++i) fa[i]=i;
for(i=1;i<=n;++i){
rd(x);rd(y);rd(z);d[x]++;d[y]++;
ix=getfa(x);iy=getfa(y);
if(ix==iy) {st=x;ed=y;vl=z;continue;}
fa[ix]=iy;lk(x,y,z);lk(y,x,z);
}
dep[1]=1;dfs(1);cir[st]=cir[ed]=true;
lk(st,ed,vl);lk(ed,st,vl);
for(x=st,y=ed;x!=y;x=fr[x]){
if(dep[x]<dep[y]) swap(x,y);
dir[fr[x]]=x;cir[fr[x]]=true;
}
lca=x;
for(x=st;;x=fr[x]) {h[++cnt]=x;if(x==lca) break;}
if(ed!=lca){
for(y=ed;;y=fr[y]) if(fr[y]==lca) break;
for(;y;y=dir[y]) h[++cnt]=y;
}
for(i=1;i<=cnt;++i){
h[cnt+i]=h[i];fr[h[i]]=0;gtdn(h[i]);
nt=(i==cnt)?1:(i+1);
for(j=head[h[i]];(to[j]!=h[nt]);j=nxt[j]);
len[i][nt]=len[nt][i]=w[j];
}
for(i=1;i<=cnt;++i){
sup[cnt+i-2]=len[trs(cnt+i-2)][trs(cnt+i-1)]+g[h[cnt+i-1]];
for(j=cnt+i-3;j>=i;--j){
sup[j]=len[trs(j)][trs(j+1)];
sup[j]+=((d[h[j+1]]-2)*g[h[j+1]]+sup[j+1])/(db)(d[h[j+1]]-1);
}
f[h[i]]=sup[i];
}
for(i=cnt+1;i<=cnt+cnt;++i){
sup[i-cnt+2]=len[trs(i-cnt+1)][trs(i-cnt+2)]+g[h[i-cnt+1]];
for(j=i-cnt+3;j<=i;++j){
sup[j]=len[trs(j-1)][trs(j)];
sup[j]+=((d[h[j-1]]-2)*g[h[j-1]]+sup[j-1])/(db)(d[h[j-1]]-1);
}
f[h[i]]+=sup[i];f[h[i]]*=0.5;
}
for(i=1;i<=cnt;++i) gtup(h[i]);
for(i=1;i<=n;++i){
if(cir[i]) ans+=(2*f[i]+(d[i]-2)*g[i])/(db)d[i];//(d[x]-2)->(d[i]-2)
else ans+=(f[i]+(d[i]-1)*g[i])/(db)d[i];
}
ans/=(db)n;
}
}
int main(){
rd(n);rd(m);
if(m==n-1) tree::sol();
else Basc::sol();
printf("%.5lf",ans);
return 0;
}