题解
注意到题目中的数是随机树,深度大概logn+层(不同的随机生成方式生成的树高应该也不同吧。。。)
怎样求以某一条边为中位数的奇数路径条数
首先,奇数数列的中位数x,满足大于它的数与小于它的数的个数相等
所以我们可以按边权从小到大加入每一条边,加入了的边边权为1,没加入的边边权为-1
那么,一条边的贡献就是它的权值*以它为中位数的路径条数
以它为中位数的路径条数可以用DP来计算
f[i][j]表示在i子树中,由 i 到x边权和为j的点x的个数
发现改变边权之后只需要更新它到根的路径上的点的DP值
计算答案的时候要注意减去由该边所在子树的贡献
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 40005
#define O 305
#define f(x,y) f[x][y+O]
int fir[N],to[2*N],nxt[2*N],cd[2*N],cnt;
void adde(int a,int b,int c)
{
to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;cd[cnt]=c;
to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;cd[cnt]=c;
}
int f[N][2*O],val[N],dep[N],fa[N];
struct node{
int x,cd;
}a[N];
bool cmp(node q,node w){return q.cd<w.cd;}
int acnt;
void dfs(int u)
{
val[u]=-1;
for(int v,p=fir[u];p;p=nxt[p]){
v=to[p];
if(v!=fa[u]){
fa[v]=u;dfs(v);
dep[u]=max(dep[u],dep[v]+1);
a[++acnt].cd=cd[p];
a[acnt].x=v;
}
}
}
int solve(int u)
{
val[u]=1;
for(int k=0,i=fa[u];i;k+=val[i],i=fa[i])
for(int j=-dep[u];j<=dep[u];j++)f(i,j+k-1)-=f(u,j),f(i,j+k+1)+=f(u,j);
int ret=0;
for(int k=val[u],i=u;fa[i];i=fa[i],k+=val[i])
for(int j=-dep[u];j<=dep[u];j++)ret+=(f(fa[i],1-(j+k))-f(i,1-(j+k)-val[i]))*f(u,j);
return ret;
}
int main()
{
freopen("draw.in","r",stdin);
freopen("draw.out","w",stdout);
int n,i,j,k,u,v,w;
scanf("%d",&n);
for(i=1;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
adde(u,v,w);
}
dfs(1);sort(a+1,a+n+1,cmp);
for(i=1;i<=n;i++)
for(j=i,k=0;j;j=fa[j],k--)
f(j,k)++;
long long ans=0;
for(i=1;i<=n;i++)
ans+=1ll*a[i].cd*solve(a[i].x);
printf("%lld",ans);
}