[POJ3162]Walking Race(DP + 单调队列)

传送门

 

题意:一棵n个节点的树。wc爱跑步,跑n天,第i天从第i个节点开始跑步,每次跑到距第i个节点最远的那个节点(产生了n个距离),现在要在这n个距离里取连续的若干天,使得这些天里最大距离和最小距离的差小于M,问怎么取使得天数最多?

 

求每个点到最远距离的点的距离可以用 computer 的方法。

至于第二问,可以跑一遍2个单调队列。

具体是固定左端点,右端点向右平移到最远,直到不能平移,再左端点向右平移一位。在这中间维护单调队列和更新 ans 最大值。

 

具体细节看代码

——代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#include <cstdio>
#include <cstring>
#include <iostream>
#define N 1000001
#define max(x, y) ((x) > (y) ? (x) : (y))
 
int n, m, cnt, h1 = 1, t1, h2 = 1, t2, ans;
int head[N], to[N << 1], val[N << 1], next[N << 1], f[N][3], a[N], q1[N], q2[N];
bool vis[N];
 
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    return x * f;
}
 
inline void add(int x, int y, int z)
{
    to[cnt] = y;
    val[cnt] = z;
    next[cnt] = head[x];
    head[x] = cnt++;
}
 
inline void dfs1(int u)
{
    int i, v, d1 = 0, d2 = 0;
    vis[u] = 1;
    for(i = head[u]; i ^ -1; i = next[i])
    {
        v = to[i];
        if(!vis[v])
        {
            dfs1(v);
            if(f[v][0] + val[i] > d1) d2 = d1, d1 = f[v][0] + val[i];
            else if(f[v][0] + val[i] > d2) d2 = f[v][0] + val[i];
        }
    }
    f[u][0] = d1;
    f[u][1] = d2;
}
 
inline void dfs2(int u)
{
    int i, v;
    vis[u] = 1;
    for(i = head[u]; i ^ -1; i = next[i])
    {
        v = to[i];
        if(!vis[v])
        {
            if(f[v][0] + val[i] == f[u][0]) f[v][2] = f[u][1] + val[i];
            else f[v][2] = f[u][0] + val[i];
            f[v][2] = max(f[v][2], f[u][2] + val[i]);
            dfs2(v);
        }
    }
}
 
int main()
{
    int i, x, y, z;
    while(~scanf("%d %d", &n, &m))
    {
        ans = cnt = 0;
        memset(f, 0, sizeof(f));
        memset(head, -1, sizeof(head));
        for(i = 1; i < n; i++)
        {
            x = read();
            y = read();
            add(i + 1, x, y);
            add(x, i + 1, y);
        }
        memset(vis, 0, sizeof(vis));
        dfs1(1);
        memset(vis, 0, sizeof(vis));
        dfs2(1);
        for(i = 1; i <= n; i++) a[i] = max(f[i][0], f[i][2]);
        for(x = 1, y = 0; x <= n; x++)
        {
            while(q1[h1] < x && h1 <= t1) h1++;
            while(q2[h2] < x && h2 <= t2) h2++;
            while(a[q1[h1]] - a[q2[h2]] < m && y <= n)
            {
                y++;
                while(a[q1[t1]] < a[y] && h1 <= t1) t1--;
                q1[++t1] = y;
                while(a[q2[t2]] > a[y] && h2 <= t2) t2--;
                q2[++t2] = y;
            }
            ans = max(ans, y - x);
        }
        printf("%d\n", ans);
    }
    return 0;
}

  

posted @   zht467  阅读(148)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示