【题解】Tree

题目戳我

( ext{Solution:})

考虑点分治。对于这个两点之间,它意味着这点对必须是不一样的。

考虑用双指针统计答案。显然,对于两个数(a,b),要让(a+b=k,a)越大则(b)越小。于是可以用双指针统计答案。

剩下的就是一个点分治板子。

GrNB!!!

#include<bits/stdc++.h>
using namespace std;
const int MAXN=2e5+10;
const int inf=(1<<30);
int tot,head[MAXN],siz[MAXN],S,k,n,sum[MAXN];
struct edge{
	int nxt,to,dis;
}e[MAXN];
int ms,mson[MAXN],rt,ans;
bitset<MAXN>vis;
inline void add(int x,int y,int w){
	e[++tot].to=y;
	e[tot].nxt=head[x];
	e[tot].dis=w;
	head[x]=tot;
}
void Gr(int x,int fa){
	siz[x]=1;mson[x]=0;
	for(int i=head[x];i;i=e[i].nxt){
		int j=e[i].to;
		if(vis[j]||j==fa)continue;
		Gr(j,x);siz[x]+=siz[j];
		if(siz[j]>mson[x])mson[x]=siz[j];
	}
	if(S-siz[x]>mson[x])mson[x]=S-siz[x];
	if(ms>mson[x])rt=x,ms=mson[x];
}
int t,tt,dis[MAXN],tr[MAXN];
void Getdis(int x,int fa,int d){
	dis[++t]=d;
	for(int i=head[x];i;i=e[i].nxt){
		int j=e[i].to;
		if(vis[j]||j==fa)continue;
		Getdis(j,x,d+e[i].dis);
	}
}
void solve(int x,int d,int fg){
	t=0;Getdis(x,0,d);
	tt=0;sort(dis+1,dis+t+1);
	int l=1,r=t;
	while(l<=r){
		if(dis[l]+dis[r]<=k){ans+=(r-l)*fg,++l;}
		else --r;
	}
}
void work(int x,int s){
	vis[x]=1;solve(x,0,1);
	for(int i=head[x];i;i=e[i].nxt){
		int j=e[i].to;
		if(vis[j])continue;
		solve(j,e[i].dis,-1);
		ms=inf;rt=0;
		S=siz[j]<siz[x]?siz[j]:(s-siz[x]);
		Gr(j,0);work(rt,S);
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;++i){
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);add(y,x,z);
	}
	scanf("%d",&k);
	rt=0;ms=inf;S=n;Gr(1,0);work(rt,S);
	printf("%d
",ans);
	return 0;
} 

第一次写的时候犯了一个浅显的错误:相加为(k)的路径并不是只找到最小的路径相匹配的最大路径即可,它并不存在一个总包含的关系。(错误要点)

原文地址:https://www.cnblogs.com/h-lka/p/13547760.html