【NOIP2016提高A组模拟8.19】(雅礼联考day2)树上路径

题目

给出一棵树,求出最小的k,使得,且在树中存在路径p,使得k>=S且k<=E。(k为路径p上的边的权值和)。

分析

点分治,设当前为x的,求在以x为根的子树中,经过x的路径(包括起点或终点在x)中长度大于等于S的最小值。
假设i有3个儿子,j、k、l,
首先将以j为根的子树中的所有点到x的距离求出来,放进队列中。排个序。
接着将以k为根的子树中的所有点到x的距离求出来,一个一个点枚举,在队列中二分,求出一段大于等于S并且最小的路径,与ans比较,取小。再将它们放进队列中。排个序。
再以j为根的子树中的所有点到x的距离求出来,同样更新答案,在再加入队列。
对于起点或终点在x的,在一开始就加入队列,就可以了。
时间复杂度(O(nlog_2^2n))
事实上菊花图卡不过,但还是水过了。

#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
const int maxlongint=2147483647;
const int mo=1000000007;
const int N=100005;
using namespace std;
int dis[N],d[N],root,last[N],next[N*2],to[N*2],v[N*2],s,e,ans=maxlongint,n,m,tot,size[N],mx,ff;
bool bz[N];
int bj(int x,int y,int z)
{
	next[++tot]=last[x];
	last[x]=tot;
	to[tot]=y;
	v[tot]=z;
}
int findroot(int x,int fa)
{
	size[x]=1;
	int num=0;
	for(int i=last[x];i;i=next[i])
	{
		int j=to[i];
		if(j!=fa && bz[j])
		{
			findroot(j,x);
			size[x]+=size[j];
			num=max(num,size[j]);
		}
	}
	num=max(ff-size[x],num);
	if(num<mx)
	{
		root=x;
		mx=num;
	} 
}
int sodis(int x,int fa,int val)
{
	d[++tot]=val;
	for(int i=last[x];i;i=next[i])
	{
		int j=to[i];
		if(j!=fa && bz[j])
		{
			sodis(j,x,val+v[i]);
		}
	}
}
int rf(int l,int r,int val)
{
	while(l<r)
	{
		int mid=(l+r)/2;
		if(d[mid]+val<s)
			l=mid+1;
		else
			r=mid;
	}
	if(d[l]+val>=s)
		ans=min(d[l]+val,ans);
	else
	if(d[r]+val>=s)
		ans=min(d[r]+val,ans);
}
int dg(int x,int fa)
{
	bz[x]=false;
	tot=1;
	d[1]=0;
	for(int i=last[x];i;i=next[i])
	{
		int j=to[i];
		if(j!=fa && bz[j])
		{
			int k=tot+1;
			sodis(j,x,v[i]);
			for(int l=k;l<=tot;l++)
			{
				rf(1,k-1,d[l]);
			}
			sort(d+1,d+1+tot);
		}
	}
	int f=tot;
	for(int i=last[x];i;i=next[i])
	{
		int j=to[i];
		if(j!=fa && bz[j])
		{
			ff=f-1;
			root=0;
			mx=maxlongint;
			findroot(j,x);
			dg(root,x);
		}
	}
}
int main()
{
	scanf("%d%d%d",&n,&s,&e);
	for(int i=1;i<=n-1;i++)
	{
		int x,y,z;
		scanf("%d%d%d",&x,&y,&z);
		bj(x,y,z);
		bj(y,x,z);
	}
	memset(bz,true,sizeof(bz));
	root=0;
	ff=n;
	mx=maxlongint;
	findroot(1,0);
	dg(root,0);
	if(ans>e)
		printf("-1
");
	else
		printf("%d
",ans);
}
原文地址:https://www.cnblogs.com/chen1352/p/9045313.html