题解

注意到题目中的数是随机树,深度大概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);
}