zoukankan      html  css  js  c++  java
  • [解题报告]ACMICPC Regionals 2011 Asia Fuzhou C Bob's Race

    Abstract

    ACM-ICPC Regionals 2011 Asia - Fuzhou C Bob's Race

    POJ4003

    树形dp 单调队列

    Body

    Source

    http://poj.org/problem?id=4003

    Description

    给定一棵N个节点的树,数列d[i] (1 <= i <= N)表示树中离点i最远的点离点i的距离。现给定Q,求d[i]的最长连续子序列的长度,使得其满足该子序列中最大最小值之差不超过Q。

    Solution

    这个题属于比较生硬的凑算法的题……问题可以分为两部分:

    1. 求数列d[i]。这里用的是非常经典的一种树形dp方法,我以前不知道叫什么,今天据章总和戴牛说叫“上下树”(好猥琐……),长春邀请赛也出了,有空可以写个专题。这种方法在对树的每个节点进行全局统计且要求复杂度为O(N)时经常用到。“上下树”的名称大概来源于这种树形dp进行两次dp,第一次自底向上(叶到根),第二次自顶向下(根到叶)。对于此题,考虑将一个点拎出来作树根后,某个点v的最远距离,要么是v向子孙节点走的最远距离,要么是其父节点u不经过(u,v)的最远距离+w(u,v)。可以把边(u,v)看作分界,u在左v在右,则前者是v往右走的最远距离,后者是v往左走的最远距离。

    因此,第一次树形dp要求出点u向子孙节点走的最远距离max1[u],向哪个子节点走最远(设为maxv[u])以及向子孙节点走的次远距离max2[u](为何要求接下来说明)。第二次树形dp对于点v,d[v]=max(x, max1[v]),其中x为v的父节点不经过(u,v)的最远距离+w(u,v)根据v是否是maxv[u],x是不一样的,因此可能用到向哪个子节点走最远(设为maxv[u])以及向子孙节点走的次远距离max2[u]。

    2. 求d[i]的最长连续子序列的长度。网上很多说用RMQ做,我太弱搞不懂为啥会用到RMQ,我用的是单调队列做的。

    显然应考察以d[i]结尾的最长子序列。假设已知以d[i-1]结尾的最长子序列X,为了求d[i]结尾的最长子序列Y,我们还需要知道X集中的最大数,设为d[j]。若|d[i]-d[j]|>Q则Y的起始下标>j且应继续考察d[j]后的最大数d[j']。若|d[i]-d[j']|>Q则Y的起始下标>j'且应继续考察d[j']后的最大数d[j'']等等。类似的还需要知道X集中的最小数d[k],d[k]后最小数d[k'],d[k']后最小数d[k'']等。这样容易得到Y。这种信息要结构化存储,而且加入d[i]后还要O(1)转移,你想到什么,反正我想到的是单调队列。事实上d[j],d[j'],d[j'']...构成的就是一个单调增队列。

    顺便,那次比赛留下了无可挽回的遗憾,家乡真是我永远的伤心之地……

    Code

    注意,STL的deque会被POJ猥琐卡常数,必须手写。

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <queue>
    #include <algorithm>
    using namespace std;
    
    int N, M, Q, ans, st;
    vector<int> adj[50050], w[50050];
    int max1[50050], max2[50050], maxv[50050];
    int d[50050];
    int inc[50050],ih, it, dec[50050], dh, dt;
    
    void init()
    {
        for (int i = 1; i <= N; ++i)
        {
            adj[i].clear();
            w[i].clear();
        }
    }
    
    inline void ae(int u, int v, int d)
    {
        adj[u].push_back(v);
        w[u].push_back(d);
        adj[v].push_back(u);
        w[v].push_back(d);
    }
    
    void dfs1(int f, int u)
    {
        max1[u] = max2[u] = maxv[u] = 0;
        int v, tmp;
        for (int i = 0; i < adj[u].size(); ++i)
        {
            v = adj[u][i];
            if (v==f) continue;
            dfs1(u, v);
            tmp = max1[v]+w[u][i];
            if (tmp >= max1[u])
            {
                max2[u] = max1[u];
                max1[u] = tmp;
                maxv[u] = v;
            }
            else if (tmp > max2[u])
                max2[u] = tmp;
        }
    }
    
    
    void dfs2(int f, int u, int l)
    {
        d[u] = max(l, max1[u]);
        int v, tmp;
        for (int i = 0; i < adj[u].size(); ++i)
        {
            v = adj[u][i];
            if (v==f) continue;
            if (v != maxv[u]) dfs2(u, v, d[u]+w[u][i]);
            else dfs2(u, v, max(max2[u], l)+w[u][i]);
        }
    }
    
    int main()
    {
        int i, j, k, u, v;
        while (scanf("%d%d", &N, &M), N||M)
        {
            init();
            for (i = 1; i < N; ++i)
            {
                scanf("%d%d%d", &u, &v, &k);
                ae(u, v, k);
            }
            dfs1(0, 1);
            dfs2(0, 1, 0);
            while (M--)
            {
                scanf("%d", &Q);
                ans = 1;
                ih = it = dh = dt = 0;
                inc[it++] = 1;
                dec[dt++] = 1;
                st = 0;
                for (i = 2; i <= N; ++i)
                {
                    j = k = st;
                    while (ih!=it && abs(d[i]-d[inc[ih]])>Q)
                        j = inc[ih++];
                    while (dh!=dt && abs(d[i]-d[dec[dh]])>Q)
                        k = dec[dh++];
                    st = max(j, k);
                    ans = max(ans, i-st);
                    while (ih!=it && d[i]<=d[inc[it-1]]) it--;
                    inc[it++] = i;
                    while (dh!=dt && d[i]>=d[dec[dt-1]]) dt--;
                    dec[dt++] = i;
                }
                printf("%d\n", ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    Eclipse集成Tomcat:6个常见的”how to”问题
    linux环境变量配置
    (原创)JS点击事件——Uncaught TypeError: Cannot set property 'onclick' of null
    [ JS 进阶 ] 闭包,作用域链,垃圾回收,内存泄露
    webstorm安装后的一些设置技巧:
    前端工程师的知识体系
    Git常用命令及软件推荐
    Vue.js双向绑定的实现原理
    GET和POST面试知识点
    CSS 巧用 :before和:after
  • 原文地址:https://www.cnblogs.com/jffifa/p/2474458.html
Copyright © 2011-2022 走看看