zoukankan      html  css  js  c++  java
  • [POJ3162]Walking Race(DP + 单调队列)

    传送门

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

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

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

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

    具体细节看代码

    ——代码

    #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
    ", ans);
        }
        return 0;
    }
    

      

  • 相关阅读:
    第二十九课 循环链表的实现
    第二十八课 再论智能指针(下)
    第二十七课 再论智能指针(上)
    第二十六课 典型问题分析(Bugfix)
    普通new和placement new的重载
    leetcode 581. Shortest Unsorted Continuous Subarray
    leetcode 605. Can Place Flowers
    leetcode 219. Contains Duplicate II
    leetcode 283. Move Zeroes
    leetcode 217. Contains Duplicate
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/7045133.html
Copyright © 2011-2022 走看看