2019マルチ大学研修コンテスト8から1006 - Acesrcと旅行 - 树形DP

http://acm.hdu.edu.cn/showproblem.php?pid=6662
ほとんど質問に書かれた木のアイデア- CCのBをモデルにしました。どこへ行く道です。

パスを行かなければならない2つは、我々は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\n", ans);
    }
    return 0;
}

それはfとgの定義は、転送サブツリー/父親から厳しくする必要がある場合は、それは特別な文を必要としないではないのですか?

おすすめ

転載: www.cnblogs.com/Yinku/p/11354020.html