自傷無色 题解
万弘
·
·
题解
套路题。
考虑Dsu on tree.
考虑加入一个 b ,对所有 a\ge b 产生贡献。 [a-b+1,a+b-1] 贡献了 2b-1 个三角,权值和为 a(2b-1)+b(2b-1)+2a(2b-1)/2 .
类似的,可以考虑对 a<b 产生贡献。
值域较大,直接的想法是用平衡树,维护和、平方和,然后单点修改区间询问。平衡树常数比较大可能是过不去的。
冷静一下发现,用到的值形如 dis_x-dis_u 的形式,其中 u 是当前求解的子树的根.用数据结构维护 dis_x ,相对大小同样不变,计算贡献时加上 -dis_u 这个偏移即可。
```cpp
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<random>
#include<chrono>
typedef long long ll;
typedef unsigned un;
typedef std::vector<int> P;
typedef std::pair<int,int> pii;
ll read(){ll x=0,f=1;char c=getchar();while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}while(c>='0'&&c<='9')x=x*10+(c-'0'),c=getchar();return f*x;}
ll max(ll a,ll b){return a>b?a:b;}
ll min(ll a,ll b){return a<b?a:b;}
template <typename T> bool umax(T& a,T t){if(t>a)return a=t,1;return 0;}
template <typename T> bool umin(T& a,T t){if(t<a)return a=t,1;return 0;}
/**********/
const int MAXN = 100011,mod = 1e9+7;
ll Qpow(ll a,ll p)
{
ll res=1;
while(p){if(p&1)res=res*a%mod;a=a*a%mod,p>>=1;}
return res;
}
struct Mint
{
int x;
Mint(){x=0;}
Mint(ll x):x((x%mod+mod)%mod) {}
Mint operator* (Mint you){return ll(x)*you.x%mod;}
Mint operator+ (Mint you){return x+you.x<mod?x+you.x:x+you.x-mod;}
void operator+= (Mint you){x+=you.x;if(x>=mod)x-=mod;}
Mint operator- (Mint you){return x-you.x<0?x-you.x+mod:x-you.x;}
void operator-= (Mint you){x-=you.x;if(x<0)x+=mod;}
};
struct edge{int v,w,nxt;}e[MAXN<<1|1];
int cnt=0,last[MAXN];
void adde(int u,int v,int w){e[++cnt].v=v,e[cnt].w=w,e[cnt].nxt=last[u],last[u]=cnt;}
int fa[MAXN],size[MAXN],ms[MAXN],diff=0;
Mint ans,c;
ll fx[MAXN],dis[MAXN];
int pos[MAXN];
std::vector<int>a[MAXN];
struct BIT
{
Mint t[MAXN],tot;
#define lowb (i&-i)
void modify(int i,Mint k)
{
tot+=k;
while(i<=diff)t[i]+=k,i+=lowb;
}
Mint Qsum(int i)
{
Mint res=0;
while(i)res+=t[i],i-=lowb;
return res;
}
}t0,t1,t2;
void dfs1(int u)
{
size[u]=1;
for(int i=last[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa[u])continue;
fa[v]=u,dis[v]=dis[u]+e[i].w, dfs1(v),size[u]+=size[v];
if(size[v]>size[ms[u]])ms[u]=v;
}
}
void calc(int u,Mint k)
{
Mint s0=t0.Qsum(pos[u]),s1=t1.Qsum(pos[u]),s2=t2.Qsum(pos[u]);
//As A
Mint A(dis[u]-k.x);
ans+=A*(s1-s0*k)*4;
ans-=A*s0*2;
ans+=(s2-s1*k*2+k*k*s0)*2;
ans-=s1-s0*k;
c+=(s1-s0*k)*2-s0;
//As b
s0=t0.tot-s0,s1=t1.tot-s1,s2=t2.tot-s2;
Mint B=A;
ans+=B*(s1-s0*k)*4;
ans-=(s1-s0*k)*2;
ans+=s0*B*B*2;
ans-=s0*B;
c+=(B*2-1)*s0;
for(int i=last[u];i;i=e[i].nxt)
if(e[i].v!=fa[u])calc(e[i].v,k);
}
void push(int u)
{
t0.modify(pos[u],1),t1.modify(pos[u],dis[u]%mod);
t2.modify(pos[u],(dis[u]%mod)*(dis[u]%mod)%mod);
for(int i=last[u];i;i=e[i].nxt)
if(e[i].v!=fa[u])push(e[i].v);
}
void back(int u)
{
t0.modify(pos[u],Mint(-1)),t1.modify(pos[u],Mint(-dis[u]));
t2.modify(pos[u],Mint(-(dis[u]%mod)*(dis[u]%mod)%mod));
for(int i=last[u];i;i=e[i].nxt)
if(e[i].v!=fa[u])back(e[i].v);
}
void solve(int u)
{
for(int i=last[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa[u]||v==ms[u])continue;
solve(v),back(v);
}
if(ms[u])solve(ms[u]);
for(int i=last[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa[u]||v==ms[u])continue;
calc(v,dis[u]),push(v);
}
t0.modify(pos[u],1),t1.modify(pos[u],dis[u]%mod);
t2.modify(pos[u],(dis[u]%mod)*(dis[u]%mod)%mod);
}
int main()
{
int n=read();
for(int i=1;i<n;++i){int u=read(),v=read(),w=read();adde(u,v,w),adde(v,u,w);}
dfs1(1);
for(int i=1;i<=n;++i)fx[++diff]=dis[i];
std::sort(fx+1,fx+diff+1),diff=std::unique(fx+1,fx+diff+1)-fx-1;
for(int i=1;i<=n;++i)pos[i]=std::lower_bound(fx+1,fx+diff+1,dis[i])-fx;
solve(1);
printf("%lld\n",(ans.x*Qpow(c.x,mod-2)%mod+mod)%mod);
return 0;
}
```