[CF846E]Chemistry in Berland题解

这题乍一看是一道水树形DP(其实事实上它确实是树形DP),然后设f[i]表示第i个点所多余/需要的材料,然后我们愉快的列出了式子:

if(f[v]<0)
	f[u] += f[v] * edges[c_e].dis;
else
	f[u] += f[v];

然后放到CF上,直接WA,十分自闭,于是我试图define int long long,还是没过,仔细一想(偷瞄了一眼CF的数据),发现f数组有可能会爆long long,怎么办?高精? 显然这不太现实,于是想着如果它要爆了就把它置回边缘,实测不会WA

贴个代码

#include <cstdio>
#define ll long long

const ll INF = (1ll << 62);

using namespace std;

inline ll read(){
    ll x = 0; int zf = 1; char ch = ' ';
    while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar();
    while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}

struct Edge{
    int to; ll dis; int next;
} edges[2000005];

int head[2000005], edge_num = 0;

inline void addEdge(int u, int v, ll dis){
    edges[++edge_num] = (Edge){v, dis, head[u]};
    head[u] = edge_num;
}

ll a[2000005], b[2000005];
ll f[2000005];

void DFS(int u){
    //置为所需 
    f[u] = b[u] - a[u];
    for(int c_e = head[u]; c_e; c_e = edges[c_e].next){
        int v = edges[c_e].to;
        DFS(v);
        if(f[v] < 0){
            //需要 u 去补 
            if (INF / edges[c_e].dis <= -f[v])
                f[u] = -INF;
            else{
                f[u] += f[v] * edges[c_e].dis;
                if (f[u] < -INF)
                    f[u] = -INF;
            }
        }
        else{
            //反向转换 
            f[u] += f[v];
        }
    }
}

int main(){
    int n = read();
    for (int i = 1; i <= n; ++i)
        b[i] = read();
    for (int i = 1; i <= n; ++i)
        a[i] = read();
    for (int i = 2; i <= n; ++i){
        int u = read(); ll dis = read();
        addEdge(u, i, dis);
    }
    DFS(1);
    if (f[1] >= 0)
        printf("YES");
    else
        printf("NO");
    return 0;
}
原文地址:https://www.cnblogs.com/linzhengmin/p/10861681.html