我们考虑每条边的贡献。
把已经走过的点染色为1,未走过的为0,那么我们对于序号序列维护一颗线段树,x-v这条边的贡献就是序列中不连续01序列包含x的个数,那么我们反过来,答案=总序列-经过x的极大连续序列,这个东西明显可以用线段树维护,维护一个从左右开始的最长01长度和最长连续就好了。
问题是直接遍历操作明显会T,我们重链剖分一下,对于一个点,先把其他的轻儿子暴力扫掉,然后再递归处理重儿子。
时间复杂度是O(nlog^2),线段树一个log+重链剖分一个log。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=1e5+5;
const int mo=1e9+7;
int n,m,head[N],next[N],go[N],size[N];
int son[N],cnt,dep[N];
typedef long long ll;
struct node
{
int l,r;
ll s;
int l0,l1,r0,r1,mx;
}t[N*5];
ll ans,ny;
inline ll pow(ll a,int b)
{
ll ret=1;
while (b)
{
if (b&1)ret=ret*a%mo;
a=a*a%mo;
b>>=1;
}
return ret;
}
inline ll get(int x)
{
return 1ll*x*(x+1)/2;
}
inline void add(int x,int y)
{
go[++cnt]=y;
next[cnt]=head[x];
head[x]=cnt;
}
inline void dfs(int x,int fa)
{
dep[x]=dep[fa]+1;
size[x]=1;
int mx=0;
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (v!=fa)
{
dfs(v,x);
size[x]+=size[v];
}
}
}
inline void dfs1(int x,int fa)
{
int k=0;
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (v!=fa)
{
if (size[v]>size[k])k=v;
}
}
if (!k)return;
son[x]=k;
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (v!=fa)dfs1(v,x);
}
}
inline void pushup(int x,int l,int r)
{
int mid=(l+r)>>1;
t[x].s=t[x<<1].s+t[x<<1|1].s-get(t[x<<1].r0)-get(t[x<<1].r1)-get(t[x<<1|1].l0)-get(t[x<<1|1].l1);
t[x].s+=get(t[x<<1].r0+t[x<<1|1].l0)+get(t[x<<1].r1+t[x<<1|1].l1);
t[x].l0=t[x<<1].l0;
t[x].l1=t[x<<1].l1;
t[x].r0=t[x<<1|1].r0;
t[x].r1=t[x<<1|1].r1;
if (t[x].l0==mid-l+1)t[x].l0+=t[x<<1|1].l0;
if (t[x].l1==mid-l+1)t[x].l1+=t[x<<1|1].l1;
if (t[x].r0==r-mid)t[x].r0+=t[x<<1].r0;
if (t[x].r1==r-mid)t[x].r1+=t[x<<1].r1;
}
inline void build(int x,int l,int r)
{
t[x].l=l,t[x].r=r;
t[x].l0=t[x].r0=r-l+1;
t[x].s=get(r-l+1);
if (l==r)return;
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
}
inline void change(int x,int pos,int v)
{
if (t[x].l==t[x].r)
{
if (!v)t[x].l0=t[x].r0=t[x].s=1,t[x].l1=t[x].r1=0;
else t[x].l1=t[x].r1=t[x].s=1,t[x].l0=t[x].r0=0;
return;
}
int mid=(t[x].l+t[x].r)>>1;
if (pos<=mid)change(x<<1,pos,v);
else change(x<<1|1,pos,v);
pushup(x,t[x].l,t[x].r);
}
inline void fill(int x,int fa,int y)
{
change(1,x,y);
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (v!=fa)fill(v,x,y);
}
}
inline void solve(int x,int fa)
{
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (v!=fa&&v!=son[x])
{
solve(v,x);
fill(v,x,0);
}
}
if (son[x])solve(son[x],x);
change(1,x,1);
for(int i=head[x];i;i=next[i])
{
int v=go[i];
if (v!=son[x]&&v!=fa)fill(v,x,1);
}
ll tot=1ll*(n+1)*n/2-t[1].s;
if (x!=1)ans=(ans+1ll*2*tot*ny)%mo;
}
int main()
{
freopen("communicate.in","r",stdin);
freopen("communicate.out","w",stdout);
scanf("%d",&n);
fo(i,1,n-1)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(1,0);
dfs1(1,0);
ny=n*(n+1)/2;
ny=pow(ny,mo-2);
build(1,1,n);
solve(1,0);
printf("%lld\n",ans);
}