• 2019 Multi-University Training Contest 8


    http://acm.hdu.edu.cn/showproblem.php?pid=6662
    仿照 CC B - TREE 那道题的思路写的,差不多。也是要走路径。

    像这两种必须走到叶子的路径感觉是必须从INF出发,使得它强制从子树转移过来。否则假如可以在中间节点中断的话,初始值就是0,转移的时候假如子树更不好就不会更新这个0。
    与哪个求每个点去往的最远点的标号(同样远的求最小标号)类似。

    f[u]表示从u节点向下走向子树的最优值,这样必须dfs到叶子然后初始化叶子再返回。
    g[u]表示从u节点向上走到父亲p,然后从父亲p绕另一条路(要么是走到祖父,要么是走到兄弟,所以f[p]要记录次优值以及最优值走向哪个儿子)的最优值,dfs的时候初始化根为它本身。

    这样子定义导致在统计答案的时候要特判。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int MAXN = 1e5 + 5;
    
    ll val[MAXN];
    
    vector<int> E[MAXN];
    
    int ROOT;
    
    void dfs1(int u, int p) {
        if(E[u].size() == 1) {
            ROOT = u;
            return;
        }
        for(auto v : E[u]) {
            if(v == p)
                continue;
            dfs1(v, u);
            if(ROOT != -1)
                return;
        }
    }
    
    const ll INF = 1e18 + 1e17;
    const ll INF2 = 1e16;
    
    struct F {
        ll val;
        int son;
    } fm1[MAXN], fm2[MAXN], fM1[MAXN], fM2[MAXN], tmpm, tmpM;
    
    inline void InitF(int n) {
        for(int i = 1; i <= n; ++i) {
            fm1[i].val = fm2[i].val = INF;
            fM1[i].val = fM2[i].val = -INF;
            fm1[i].son = fm2[i].son = fM1[i].son = fM2[i].son = -1;
        }
    }
    
    void maintainF(int u, int v) {
        if(tmpM.val < fm2[u].val) {
            fm2[u] = tmpM;
            fm2[u].son = v;
            if(fm2[u].val < fm1[u].val) {
                swap(fm1[u], fm2[u]);
            }
        }
        if(tmpm.val > fM2[u].val) {
            fM2[u] = tmpm;
            fM2[u].son = v;
            if(fM2[u].val > fM1[u].val) {
                swap(fM1[u], fM2[u]);
            }
        }
    }
    
    void dfsF(int u, int p) {
        if(E[u].size() == 1 && E[u][0] == p) {
            fm1[u].val = val[u];
            fM1[u].val = val[u];
            fm1[u].son = u;
            fM1[u].son = u;
            return;
        }
        for(auto v : E[u]) {
            if(v == p)
                continue;
            dfsF(v, u);
            tmpM = fM1[v];
            tmpm = fm1[v];
            maintainF(u, v);
        }
        fm1[u].val += val[u];
        fm2[u].val += val[u];
        fM1[u].val += val[u];
        fM2[u].val += val[u];
    }
    
    struct G {
        ll val;
    } gm[MAXN], gM[MAXN];
    
    inline void InitG(int n) {
        for(int i = 1; i <= n; ++i) {
            gm[i].val = INF;
            gM[i].val = -INF;
        }
    }
    
    F getFm(int u, int p) {
        if(fm1[p].son == u)
            return fm2[p];
        return fm1[p];
    }
    
    F getFM(int u, int p) {
        if(fM1[p].son == u)
            return fM2[p];
        return fM1[p];
    }
    
    void maintainG(int u, int p) {
        if(p == -1) {
            gm[u].val = val[u];
            gM[u].val = val[u];
            return;
        }
        gm[u].val = max(getFM(u, p).val, gM[p].val) + val[u];
        gM[u].val = min(getFm(u, p).val, gm[p].val) + val[u];
    }
    
    void dfsG(int u, int p) {
        maintainG(u, p);
        for(auto v : E[u]) {
            if(v == p)
                continue;
            dfsG(v, u);
        }
    }
    
    int main() {
    #ifdef Yinku
        freopen("Yinku.in", "r", stdin);
    #endif // Yinku
        int T;
        scanf("%d", &T);
        while(T--) {
            int n;
            scanf("%d", &n);
            for(int i = 1; i <= n; ++i)
                scanf("%lld", &val[i]);
            for(int i = 1, b; i <= n; ++i) {
                scanf("%d",  &b);
                val[i] -= b;
            }
            for(int i = 1; i <= n; ++i)
                E[i].clear();
            for(int i = 1; i <= n - 1; ++i) {
                int u, v;
                scanf("%d%d", &u, &v);
                E[u].push_back(v);
                E[v].push_back(u);
            }
            ROOT = -1;
            dfs1(1, -1);
            //ROOT是其中一个叶子
            InitF(n);
            dfsF(ROOT, -1);
            InitG(n);
            dfsG(ROOT, -1);
            ll ans = -INF;
            for(int i = 1; i <= n; ++i) {
                ll tmp = (E[i].size() == 1 && i != ROOT ? INF : fm1[i].val);
                tmp = min(tmp, (i != ROOT) ? (gm[i].val) : INF);
                ans = max(ans, tmp);
            }
            printf("%lld
    ", ans);
        }
        return 0;
    }
    

    假如定义f和g不包含节点本身的话,那是不是不需要特判呢?只能说是判得更恶心了。

  • 相关阅读:
    photoshop快捷键汇总
    div和css:行内元素和块元素的水平和垂直居中
    使块元素并排显示和清除浮动的方法
    javascript与DOM节点的结合使用
    导航+轮播图(手动)
    执行计划
    oracle存储过程
    oracle 常用语法
    Sqlserver数据库总结
    sqlserver sum 和count在关于进行统计时的区别
  • 原文地址:https://www.cnblogs.com/Yinku/p/11354020.html
Copyright © 2020-2023  润新知