POJ 3162 树形dp+线段树

Walking Race
Time Limit: 10000MS Memory Limit: 131072K
Total Submissions: 2524 Accepted: 606
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 hasN 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 lastsN 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 fromN 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 boundM. 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 integersN (N ≤ 106) and M (M < 109). Then followN − 1 lines, each containing two integers fi and di (i = 1, 2, …, N − 1), meaning the check-points i + 1 andfi 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.

题意:给定一张地图,它是一棵n个节点的树。mm爱跑步,mm要跑n天,每次都从一个结点开始跑步,每次都要跑到最远的那个结点,两天跑的最远距离有个差值,现在要从这n天里去若干天使得这些天的差值都小于m,问怎么取使得天数最多?n <= 100万,m <= 1亿。

首先树形dp求出每个点到其他所有点的最远距离,然后线段树维护最大值,最小值,然后维护两个指针,扫描一遍,貌似也可以单调队列,我勒个大去,数据量好大,采用系统的max,min函数,tle无极限,只好自己定义函数。

线段树维护代码:

/* ***********************************************
Author :xianxingwuguan
Created Time :2014-2-11 11:57:36
File Name :1.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <string>
#include <time.h>
#include <math.h>
#include <queue>
#include <stack>
#include <set>
#include <map>
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
const int maxn=1000100;
int head[maxn],tol,dp[maxn][3],n,m;
struct node{
	int next,to,val;
	node(){};
	node(int _next,int _to,int _val):next(_next),to(_to),val(_val){}
}edge[4*maxn];
void add(int u,int v,int w){
	edge[tol]=node(head[u],v,w);
	head[u]=tol++;
}
int MAX(int x,int y){
	if(x>=y)return x;
	return y;
}
int MIN(int x,int y){
	if(x<=y)return x;
	return y;
}
void dfs1(int u,int fa){
	int b1=0,b2=0;
	dp[u][0]=dp[u][1]=dp[u][2]=0;
	for(int i=head[u];i!=-1;i=edge[i].next){
		int v=edge[i].to;
		if(v==fa)continue;
		dfs1(v,u);
		int ret=dp[v][0]+edge[i].val;
		if(ret>=b1){
			b2=b1;
			b1=ret;
		}
		else if(ret>=b2)b2=ret;
	}
	dp[u][0]=b1;
	dp[u][1]=b2;
}
void dfs2(int u,int fa){
	 for(int i=head[u];i!=-1;i=edge[i].next){
		 int v=edge[i].to;
		 if(v==fa)continue;
		 dp[v][2]=max(dp[u][2],dp[v][0]+edge[i].val==dp[u][0]?dp[u][1]:dp[u][0])+edge[i].val;
		 dfs2(v,u);
	 }
}
struct NODE{
	int l,r,max,min;
}tree[5*maxn];
void build(int l,int r,int i){
	tree[i].l=l;
	tree[i].r=r;
	if(l==r){
		tree[i].max=MAX(dp[l][0],dp[l][2]);
		tree[i].min=tree[i].max;
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,2*i);
	build(mid+1,r,2*i+1);
	tree[i].max=MAX(tree[2*i].max,tree[2*i+1].max);
	tree[i].min=MIN(tree[2*i].min,tree[2*i+1].min);

}
int query_max(int l,int r,int i){
	if(tree[i].l>=l&&tree[i].r<=r)return tree[i].max;
	int mid=(tree[i].l+tree[i].r)>>1;
	int ans=0;
	if(l<=mid)ans=MAX(ans,query_max(l,r,2*i));
	if(r>mid)ans=MAX(ans,query_max(l,r,2*i+1));
	return ans;
}
int query_min(int l,int r,int i){
	if(tree[i].l>=l&&tree[i].r<=r)return tree[i].min;
	int mid=(tree[i].l+tree[i].r)>>1;
	int ans=INF;
	if(l<=mid)ans=MIN(ans,query_min(l,r,2*i));
	if(r>mid)ans=MIN(ans,query_min(l,r,2*i+1));
	return ans;
}
int main()
{
     //freopen("data.in","r",stdin);
     //freopen("data.out","w",stdout);
     int i,j,k;
	 while(~scanf("%d%d",&n,&m)){
		 memset(head,-1,sizeof(head));tol=0;
		 for(i=2;i<=n;i++){
			 scanf("%d%d",&j,&k);
			 add(i,j,k);
			 add(j,i,k);
		 }
		 dfs1(1,-1);
		 dfs2(1,-1);
		// for(i=1;i<=n;i++)cout<<max(dp[i][0],dp[i][2])<<" ";cout<<endl;
		 build(1,n,1);
	//	 while(cin>>i>>j)cout<<query_max(i,j,1)<<" "<<query_min(i,j,1)<<endl;

		 int ans=1,l=1,r=1;
		 while(r<=n){
			 int minn=query_min(l,r,1);
			 int maxx=query_max(l,r,1);
			 if(maxx-minn<=m){
				 ans=MAX(ans,r-l+1);
				 r++;
			 }
			 while(maxx-minn>m){
				 l++;
				 minn=query_min(l,r,1);
			     maxx=query_max(l,r,1);
			 }
		 }
		 cout<<ans<<endl;
		 
	 }
     return 0;
}
/*
C:\WINDOWS\system32\cmd.exe /c  1
12 6
1 2
2 4
2 2
1 6
1 5
6 1
6 1
7 2
7 3
10 1
11 4
14 16 22 22 20 11 13 21 23 18 19 23
5
*/ 


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述 给出一个$n\times m$的矩阵,每个位置上有一个非负整数,代表这个位置的海拔高度。一开始时,有一个人站在其中一个位置上。这个人可以向上、下、左、右四个方向移动,但是只能移动到海拔高度比当前位置低或者相等的位置上。一次移动只能移动一个单位长度。定义一个位置为“山顶”,当且仅当从这个位置开始移动,可以一直走到海拔高度比它低的位置上。请问,这个矩阵中最多有多少个“山顶”? 输入格式 第一行两个整数,分别表示$n$和$m$。 接下来$n$行,每行$m$个整数,表示整个矩阵。 输出格式 输出一个整数,表示最多有多少个“山顶”。 样例输入 4 4 3 2 1 4 2 3 4 3 5 6 7 8 4 5 6 7 样例输出 5 算法1 (递归dp) $O(nm)$ 对于这道题,我们可以使用递归DP来解决,用$f(i,j)$表示以$(i,j)$为起点的路径最大长度,那么最后的答案就是所有$f(i,j)$中的最大值。 状态转移方程如下: $$ f(i,j)=\max f(x,y)+1(x,y)是(i,j)的下一个满足条件的位置 $$ 注意:这里的状态转移方程中的$x,y$是在枚举四个方向时得到的下一个位置,即: - 向上:$(i-1,j)$ - 向下:$(i+1,j)$ - 向左:$(i,j-1)$ - 向右:$(i,j+1)$ 实现过程中需要注意以下几点: - 每个点都需要搜一遍,因此需要用双重for循环来枚举每个起点; - 对于已经搜索过的点,需要用一个数组$vis$来记录,防止重复搜索; - 在进行状态转移时,需要判断移动后的点是否满足条件。 时间复杂度 状态数为$O(nm)$,每个状态转移的时间复杂度为$O(1)$,因此总时间复杂度为$O(nm)$。 参考文献 C++ 代码 算法2 (动态规划) $O(nm)$ 动态规划的思路与递归DP类似,只不过转移方程和实现方式有所不同。 状态转移方程如下: $$ f(i,j)=\max f(x,y)+1(x,y)是(i,j)的下一个满足条件的位置 $$ 注意:这里的状态转移方程中的$x,y$是在枚举四个方向时得到的下一个位置,即: - 向上:$(i-1,j)$ - 向下:$(i+1,j)$ - 向左:$(i,j-1)$ - 向右:$(i,j+1)$ 实现过程中需要注意以下几点: - 每个点都需要搜一遍,因此需要用双重for循环来枚举每个起点; - 对于已经搜索过的点,需要用一个数组$vis$来记录,防止重复搜索; - 在进行状态转移时,需要判断移动后的点是否满足条件。 时间复杂度 状态数为$O(nm)$,每个状态转移的时间复杂度为$O(1)$,因此总时间复杂度为$O(nm)$。 参考文献 C++ 代码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值