POJ 3162

Walking Race

Time Limit: 10000MS   Memory Limit: 131072K
Total Submissions: 5433   Accepted: 1377
Case Time Limit: 3000MS

Description

flymouse’s sister wc is very capable at sports and her favorite event is walking race. Chasing after the championship in an important competition, she comes to a training center to attend a training course. The center has N check-points numbered 1 through N. Some pairs of check-points are directly connected by two-way paths. The check-points and the paths form exactly a tree-like structure. The course lasts N days. On the i-th day, wc picks check-point i as the starting point and chooses another check-point as the finishing point and walks along the only simple path between the two points for the day’s training. Her choice of finishing point will make it that the resulting path will be the longest among those of all possible choices.

After every day’s training, flymouse will do a physical examination from which data will obtained and analyzed to help wc’s future training be better instructed. In order to make the results reliable, flymouse is not using data all from N days for analysis. flymouse’s model for analysis requires data from a series of consecutive days during which the difference between the longest and the shortest distances wc walks cannot exceed a bound M. The longer the series is, the more accurate the results are. flymouse wants to know the number of days in such a longest series. Can you do the job for him?

Input

The input contains a single test case. The test case starts with a line containing the integers N (N ≤ 106) and M (M < 109). Then follow N − 1 lines, each containing two integers fi and di (i = 1, 2, …, N − 1), meaning the check-points i + 1 and fi are connected by a path of length di.

Output

Output one line with only the desired number of days in the longest series.

Sample Input

3 2
1 1
1 3

Sample Output

3

Hint

Explanation for the sample:

There are three check-points. Two paths of lengths 1 and 3 connect check-points 2 and 3 to check-point 1. The three paths along with wc walks are 1-3, 2-1-3 and 3-1-2. And their lengths are 3, 4 and 4. Therefore data from all three days can be used for analysis.

Source

POJ Monthly--2006.12.31, flymouse

 

大致题意:

给一棵n个结点边带权的树,记结点i到其他结点最远距离为d[i]。

问d数组构成的这个序列中满足其中最大值与最小值的差不超过m的连续子序列最长是多长。

解题思路:

树形dp来求树中的每个顶点到其他所有顶点距离的最大值。然后用单调队列求满足max-min<=m的连续子序列最长是多长。

题意:给你一棵有n个节点的树,树边为权值,要你求出树上每个点到其他点的距离中最大的那个值。对求出的从节点1到节点n最大值,找出最长的一段使得这一段中最大值减最小值的结点小于等于m。

对于第一个问题,有两种方法可以解决。第一种比较简单的方法是,每个点到其他点的距离中最大的那个值,一定是到树的直径的两个端点的距离之一(反证法易得)。那么我们找出树的直径的同时,处理出各个节点到树直径两个端点的距离就可以了。第二种方法是树型DP,两次DFS,第一次DFS求出以点i为根节点的子树里,到达点i的最大距离。但是我们所要求的最大距离也可能在父节点的分支中,所以用第二次DFS处理出,具体的细节参照代码。

对于第二个问题,同样有两种方法,一是线段树,扫一次就可以,二是单调队列,维护一个单调增的队列,一个单调减的队列,觉得很巧妙啊。

代码:

1.树型DP加线段树
 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define INF ((LL)1<<60)
#define MID(a,b) (a+((b-a)>>1))
const int N=1e6+5;
struct Edge
{
	int v,wei,pre;
	Edge(){}
	Edge(int a,int b,int c){v=a;pre=b;wei=c;}
}edge[N*2];
struct node
{
	int lft,rht;
	LL mi,mx;
	int mid(){return MID(lft,rht);}
};
 
int head[N],tot;
LL f1[N],f2[N];
int g1[N],g2[N];
 
void iswap(int u)
{
	if(f1[u]<f2[u])
	{
		swap(f1[u],f2[u]);
		swap(g1[u],g2[u]);
	}
}
void addEdge(int u,int v,int wei)
{
	edge[tot]=Edge(v,head[u],wei);
	head[u]=tot++;
}
void dfs_1(int u,int fa)
{
	f1[u]=f2[u]=0;
	for(int i=head[u];i!=-1;i=edge[i].pre)
	{
		int v=edge[i].v,wei=edge[i].wei;
		if(v==fa) continue;
		dfs_1(v,u);
		if(f2[u]<f1[v]+wei)
		{
			f2[u]=f1[v]+wei;
			g2[u]=v;
			iswap(u);
		}
	}
}
void dfs_2(int u,int fa)
{
	for(int i=head[u];i!=-1;i=edge[i].pre)
	{
		int v=edge[i].v,wei=edge[i].wei;
		if(v==fa) continue;
		if(g1[u]==v)
		{
			if(f2[v]<f2[u]+wei)
			{
				f2[v]=f2[u]+wei;
				g2[v]=u;
				iswap(v);
			}
		}
		else 
		{
			if(f2[v]<f1[u]+wei);
			{
				f2[v]=f1[u]+wei;
				g2[v]=u;
				iswap(v);
			}
		}
		dfs_2(v,u);
	}
}
 
struct Segtree
{
	node tree[N*4];
	void build(int lft,int rht,int ind)
	{
		tree[ind].lft=lft;	tree[ind].rht=rht;
		tree[ind].mi=INF;	tree[ind].mx=-INF;
		if(lft==rht) tree[ind].mi=tree[ind].mx=f1[lft];
		else 
		{
			int mid=tree[ind].mid();
			build(lft,mid,LL(ind));
			build(mid+1,rht,RR(ind));
			tree[ind].mi=min(tree[LL(ind)].mi,tree[RR(ind)].mi);
			tree[ind].mx=max(tree[LL(ind)].mx,tree[RR(ind)].mx);
		}
	}
	void query(int st,int ed,int ind,LL &mi,LL &mx)
	{
		int lft=tree[ind].lft,rht=tree[ind].rht;
		if(st<=lft&&rht<=ed) 
		{
			mi=tree[ind].mi,mx=tree[ind].mx;
			return ;
		}
		else 
		{
			int mid=tree[ind].mid();
			LL mi1=INF,mi2=INF,mx1=-INF,mx2=-INF;
			if(st<=mid) query(st,ed,LL(ind),mi1,mx1);
			if(ed>mid) query(st,ed,RR(ind),mi2,mx2);
			mi=min(mi1,mi2); mx=max(mx1,mx2);
			return ;
		}
	}
}seg;
 
int main()
{
	int n,m;
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		tot=0;
		memset(head,-1,sizeof(head));
		for(int i=2;i<=n;i++)
		{
			int x,y;
			scanf("%d%d",&x,&y);
			addEdge(i,x,y);
			addEdge(x,i,y);
		}
		dfs_1(1,-1); dfs_2(1,-1);
 
		int st=1,ed=1,res=0;
		LL mi,mx;
		seg.build(1,n,1);
		while(ed<=n)
		{
			seg.query(st,ed,1,mi,mx);
			if(mx-mi<=m) 
			{
				res=max(res,ed-st+1);
				ed++; 
			}
			while(mx-mi>m)
			{
				st++;
				seg.query(st,ed,1,mi,mx);
			}
		}
		printf("%d\n",res);
	}
	return 0;
}

2.DFS加单调队列

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=1e6+5;
struct Edge
{
	int v,wei,pre;
	Edge(){}
	Edge(int a,int b,int c){v=a;pre=b;wei=c;}
}edge[N*2];
 
int head[N],tot,n,m;
int dx[N],dy[N],d[N];
int qmin[N],qmax[N];
 
void addEdge(int u,int v,int wei)
{
	edge[tot]=Edge(v,head[u],wei);
	head[u]=tot++;
}
void dfs(int u,int fa,int dis,int *d)
{
	for(int i=head[u];i!=-1;i=edge[i].pre)
	{
		int v=edge[i].v,wei=edge[i].wei;
		if(v!=fa) dfs(v,u,d[v]=dis+wei,d);
	}
}
void solve()
{
	int ans=0,i,j,front1,front2,rear1,rear2;
	front1=rear1=0;
	front2=rear2=0;
 
	for(i=1,j=1;j<=n;j++)
	{
		while(rear1>front1&&d[qmax[rear1-1]]<=d[j]) rear1--;
		qmax[rear1++]=j;
 
		while(rear2>front2&&d[qmin[rear2-1]]>=d[j]) rear2--;
		qmin[rear2++]=j;
 
		if(d[qmax[front1]]-d[qmin[front2]]>m)
		{
			ans=max(ans,j-i);
			while(d[qmax[front1]]-d[qmin[front2]]>m)
			{
				i=min(qmax[front1],qmin[front2])+1;
				while(rear1>front1&&qmax[front1]<i) front1++;
				while(rear2>front2&&qmin[front2]<i) front2++;
			}
		}
	}
	ans=max(ans,j-i);
	printf("%d\n",ans);
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		tot=0;
		memset(head,-1,sizeof(head));
 
		int x,y,i;
		for(int i=2;i<=n;i++)
		{
			scanf("%d%d",&x,&y);
			addEdge(i,x,y);
			addEdge(x,i,y);
		}
		dfs(1,0,d[1]=0,d);
		for(x=1,i=2;i<=n;i++)
			if(d[i]>d[x]) x=i;
		dfs(x,0,dx[x]=0,dx);
		for(y=1,i=2;i<=n;i++)
			if(dx[i]>dx[y]) y=i;
		dfs(y,0,dy[y]=0,dy);
 
		for(int i=1;i<=n;i++) d[i]=max(dx[i],dy[i]);
		solve();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40421671/article/details/88780076
POJ