• 51nod 1789 跑的比谁都快


     
    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    #include <stack>
    #define MAXN 100050
    #define INF 2000000000000000000LL
    #define LL long long
    using namespace std;
    int n, p, numEdge, top, root;
    bool lef[MAXN];
    int head[MAXN], star[MAXN];
    LL dp[MAXN], ans;
    struct Edge
    {
        int v, next;
    }edge[MAXN];
    void addEdge(int u, int v)
    {
        edge[numEdge].v = v;
        edge[numEdge].next = head[u];
        head[u] = numEdge++;
    }
    struct Node
    {
        int id, l, r;
        Node(int I = 0, int L = 0, int R = 0): id(I), l(L), r(R){};
    }S[MAXN];
    LL quickPow(LL a, LL b)
    {
        LL res = 1LL;
        while(b)
        {
            if(b & 1) res *= a;
            a *= a;
            b >>= 1;
        }
        return res;
    }
    LL work(int i, int j)
    {
        return quickPow(j - i, p) + (LL)star[i];
    }
    void dfs(int u)
    {
        stack<Node> tmp;
        int tmpR = -1;
        int lft = 1, rit = top, mid;
        if(u == root)
        {
            dp[u] = 0;
            S[++top] = Node(root, 1, n);
        }
        else
        {
            while(lft <= rit)                    //初始化dp[u]
            {
                mid = (lft + rit) >> 1;
                if(S[mid].l <= u && u <= S[mid].r)
                {
                    dp[u] = dp[S[mid].id] + work(S[mid].id, u);
                    break;
                }
                if(u < S[mid].l) rit = mid - 1;
                else   lft = mid + 1;
            }
            while(top > 0)                        //决策单调性的经典操作
            {
                if(dp[S[top].id] + work(S[top].id, S[top].l) < dp[u] + work(u, S[top].l))
                {
                    lft = S[top].l, rit = S[top].r;
                    while(lft <= rit)            //二分找出breakpoint
                    {
                        mid = (lft + rit) >> 1;
                        if(dp[S[top].id] + work(S[top].id, mid) < dp[u] + work(u, mid))
                            lft = mid + 1;
                        else
                            rit = mid - 1;
                    }
                    tmpR = S[top].r;
                    S[top].r = rit;
                    break;
                }
                tmp.push(S[top]);                                //记录下从栈中撤出的元素到tmp中
                top--;
            }
            if(lft <= n) S[++top] = Node(u, lft, n);
        }
        if(head[u] == -1) ans = min(ans, dp[u]);
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].v;
            dfs(v);
        }
        if(u != root)
        {
            if(lft <= n) top--;
            if(tmpR != -1) S[top].r = tmpR;
            while(!tmp.empty())                                    //回溯的时候恢复栈
            {
                S[++top] = tmp.top();
                tmp.pop();
            }
        }
    }
    int main()
    {
        scanf("%d%d", &n, &p);
        star[0] = numEdge = top = 0;
        for(int i = 0; i <= n; i++) head[i] = -1, lef[i] = true;
        root = 1;
        for(int fa, i = 1; i <= n; i++)
        {
            scanf("%d%d", &star[i], &fa);
            addEdge(fa, i);
            lef[fa] = false;
        }
        ans = INF;
        dfs(root);
        cout << ans << endl;
        return 0;
    }
    View Code

    题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1789

    一个很明显的树上dp 不过对于  维护每条链 就行了

    问题在于如何优化 这是个很伤脑筋的问题,看了一个其他人的代码,还是不理解那边二分的作用是啥!QAQ

    还是菜啊~

    好了,终于明白了那大概是个什么玩意儿了! 这是一种决策性单调dp,采用的是单调栈的优化

    相当于是广义的单调栈吧(口胡)

    二分的作用是为了找出那个栈所含括的点,也就是栈里那个元素表示最优的最大区间(当然在程序没有结束前都只是暂时最优,也就是说右区间是可以修改的)

    设那个元素为elem 那么如果elem.l >= elem.r 那么显然这个元素可以被踢出栈去了

    可以二分的原因在于因为这是单调的(其实得事先证明的)

    为什么我认为它是广义的单调栈呢?

    因为我们普通的栈优化其实每次每个栈元素对应的区间是 elem.r = n的,所以不需要记录。

    详情请见:

    1D/1D动态规划优化初步

    http://wenku.baidu.com/link?url=wJZ5nc-evTz4OjhPRD8yA6zZUeANcrngwYRMOAAySeCXBFvyAcrFHusd1cG3Yz8A5Ez-whuHY6nV55tx9yYLVzHJKPegne2iOZqSzqWHYbu

  • 相关阅读:
    Django部署在CENTOS7上
    慕课DJANGO配置
    响应式布局组件介绍
    SYN泛洪攻击原理及防御
    Token,session,cookie
    -webkit-
    JS中dataTransfer对象在拖曳操作中的妙用。
    深入理解DOM节点类型第一篇——12种DOM节点类型概述
    js如何打印object对象
    cookie(2)
  • 原文地址:https://www.cnblogs.com/boson-is-god/p/6243141.html
Copyright © 2020-2023  润新知