P6992 [NEERC2014] Hidden Maze 题解
经典题。
我们称边上的原权为边的值,后面赋的权为边的权。考虑弱化一下,如何求中位数恰为
路径和这种东西可以点分,但不好扩展和处理恰经过的条件,考虑 dp,设
怎么扩展呢,如果我们按边的值顺次加入边,那么每次只会影响祖先的
时间复杂度考虑一个点被重构的次数和单次复杂度,为
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#define P 250
#define ll long long
using namespace std;
int n,m;
int stk[P+5];
int ww[30005];
int fa[30005];
int mde[30005];
int dep[30005];
int f[30005][P*2+5];
vector <int> g[30005];
struct node{int u,v,w;}e[30005];
ll all;
inline void in(int &n){
n=0;
char c=getchar();
while(c<'0' || c>'9') c=getchar();
while(c>='0'&&c<='9') n=n*10+c-'0',c=getchar();
return ;
}
inline pair <int,int> dfs(int u,int fath){
fa[u]=fath;
dep[u]=dep[fa[u]]+1;
mde[u]=0;
f[u][P]=1;
int s1=0,s2=0;
if(dep[u]&1) s1++;
else s2++;
for(int v:g[u]){
if(v==fath) continue;
ww[v]=-1;
auto tmp=dfs(v,u);
mde[u]=max(mde[u],mde[v]+1);
all+=s1*tmp.second+s2*tmp.first;
s1+=tmp.first,s2+=tmp.second;
for(int i=-mde[u];i<=mde[u];i++) f[u][i+P]+=f[v][i+1+P];
}
return {s1,s2};
}
signed main(){
in(n);
for(int i=1;i<n;i++){
in(e[i].u),in(e[i].v),in(e[i].w);
g[e[i].u].emplace_back(e[i].v);
g[e[i].v].emplace_back(e[i].u);
}
dfs(1,0);
sort(e+1,e+n,[](node p,node q){return p.w<q.w;});
ll ans=0,S=0;
for(int i=1;i<n;i++){
int u=e[i].u,v=e[i].v;
if(dep[u]<dep[v]) swap(u,v);
ans=0;
int top=0,uu=fa[u],s=1;
stk[0]=u;
while(uu) stk[++top]=uu,s+=ww[uu],uu=fa[uu];
for(int d=top;d>=1;d--){
int U=stk[d],V=stk[d-1];
for(int j=-mde[U];j<=mde[U];j++) f[U][j+P]-=f[V][j-ww[V]+P];
for(int j=-mde[U];j<=mde[U];j++){
int x=1-j-s;
if(x<-P||x>P) continue;
ans+=f[U][j+P]*f[u][x+P];
}
s-=ww[V];
}
S+=e[i].w*ans;
ww[u]=1;
int U=fa[u],V=u;
while(U){
for(int j=-mde[U];j<=mde[U];j++) f[U][j+P]+=f[V][j-ww[V]+P];
U=fa[U],V=fa[V];
}
}
printf("%.9lf\n",1.0*S/all);
return 0;
}