POJ3162-Walking Race

题目:

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 Ndays. 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 fiare 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.

 

题目大意:

给定一棵树,对于这棵树从1到n的每一个结点,在树上都能找到一个距离它最远的结点,记录从1到n这n个结点的最长距离dis[i],要求一段区间,满足这段区间内dis的最大值与最小值之差小于等于m,求这一段连续区间最长能是多长。

 

解题思路:

先用树形DP求出每个点能到达的最远距离,然后再使用两个单调队列,一个维护最大值,一个维护最小值,这样就能求出最长区间了。

树形DP求最远距离:两次dfs,一次由叶子转移到树根,一次由树根转移到叶子。

第一次dfs求出该结点到它的子节点的最远距离。

第二次dfs求出从该结点向上走能到达的最远距离。

对于第二次dfs的向上走,我们有可能在往上走k个结点之后,就又开始往下走,那往上走是只有唯一一条路径的,那么这段路径能求出来,而往下走的最远距离,就能用到我们第一次dfs求得的该结点的最远距离了。十分巧妙

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<map>
#include<queue>

using namespace std;
const long long inf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1000005;

int n, m, k;

struct Edge
{
    int to,nxt;
    long long w;
} edges[maxn<<2];
int head[maxn<<2];
int tot;

void addEdge(int u, int v, long long w)
{
    edges[tot] = Edge{v,head[u],w};
    head[u] = tot++;
}

long long dp1[maxn]; //从该结点往下走能走的最远距离
long long dp2[maxn]; //从该节点往上走能走的最远距离

void dfs1(int u, int fa)
{
    for(int i = head[u]; ~i; i = edges[i].nxt)
    {
        int to = edges[i].to;
        long long w = edges[i].w;
        if(to == fa)
            continue;
        dfs1(to,u);
        dp1[u] = max(dp1[u],dp1[to]+w);
    }
}

void dfs2(int u, int fa, int ancestor, long long d) //当前结点,当前结点父亲,当前结点爷爷,父亲到当前点距离
{
    dp2[u] = dp2[fa];
    for(int i = head[fa]; ~i; i = edges[i].nxt)
    {
        int to = edges[i].to;
        long long w = edges[i].w;
        if(to == u||to==ancestor)
            continue;
        dp2[u] = max(dp2[u],w+dp1[to]);
    }
    dp2[u]+=d;
    for(int i = head[u]; ~i; i = edges[i].nxt)
    {
        int v = edges[i].to;
        long long w = edges[i].w;
        if(v == fa) continue;
        dfs2(v,u,fa,w);
    }
}

long long qb[maxn];
long long qs[maxn];

int main()
{
    int n;
    long long m;
    scanf("%d%lld", &n, &m);
    int u, v;
    long long w;
    memset(head,-1,sizeof(head));
    tot = 1;
    for(u = 2; u <= n; u++)
    {
        scanf("%d%lld", &v, &w);
        addEdge(u,v,w);
        addEdge(v,u,w);
    }
    dfs1(1,0);
    dfs2(1,0,-1,0);
    for(int i = 1; i <= n; i++){
        dp1[i] = max(dp1[i],dp2[i]);
//        cout << dp1[i]<<" ";
    }
//    cout <<endl;

    int headb = 1,tailb = 0, heads = 1, tails = 0;
    int ans = 0;
    int minn = 0;
    for(int i = 1; i <= n; i++)
    {
        while(tailb>=headb&&dp1[i]>dp1[qb[tailb]])tailb--;
        qb[++tailb] = i;
        while(tails>=heads&&dp1[i]<dp1[qs[tails]])tails--;
        qs[++tails] = i;

        while(dp1[qb[headb]]-dp1[qs[heads]]>m)
        {
            minn = min(qb[headb],qs[heads]);
            if(minn == qb[headb])headb++;
            if(minn == qs[heads])heads++;
        }
        ans = max(ans,i-minn);
    }
    printf("%d\n", ans);
    return 0;
}

7 4
1 8
1 4
2 2
2 3
3 6
3 3

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值