关于假作法

P4383 [八省联考 2018] 林克卡特树

Smallbasic @ 2022-12-31 11:45:06

luogu上能过,但是LOJ上只有85分,请问是wqs二分的问题还是dp(f[i][0/1/2] 表示 i 下面连了 0/1/2 条边)的问题?正确做法是什么啊qwq

#include <bits/stdc++.h>

using namespace std;

const int N = 3e5 + 5;

typedef long long ll;

const ll inf = 1e18;

ll C = 0;

struct node {
    ll v; int k;
    inline node(ll V, int K) : v(V), k(K) { }
    inline node() { v = -1e18; k = 0; }
    inline bool operator > (const node &b) const { return v + C * k == b.v + C * b.k ? k < b.k : v + C * k > b.v + C * b.k; }
    inline bool operator < (const node &b) const { return v + C * k == b.v + C * b.k ? k > b.k : v + C * k < b.v + C * b.k; }
};

inline node operator + (node a, node b) { return node(a.v + b.v, a.k + b.k); }
inline node operator - (node a, node b) { return node(a.v - b.v, a.k - b.k); }

template<typename T> inline T max_(T a, T b) { return a > b ? a : b; } 

node f[N][3];

struct edge {
    int head, to, nxt, val;
} ed[N << 1];

int en = 0;

inline void addedge(int from, int to, int val) {
    ed[++en].to = to; ed[en].val = val; ed[en].nxt = ed[from].head; ed[from].head = en;
}

inline void dfs(int now, int fa) {
    f[now][0] = node(0, 0);
    f[now][1] = node(-inf, 0);
    f[now][2] = node(0, 1);
    for (int i = ed[now].head; i; i = ed[i].nxt) {
        int v = ed[i].to;
        if (v == fa) continue;
        dfs(v, now);
        node tmp;
        tmp = f[now][2];
        for (int j = 0; j < 3; ++j) f[now][2] = max_(f[now][2], tmp + f[v][j]);
        f[now][2] = max_(f[now][2], f[now][1] + f[v][0] + node(ed[i].val, 0));
        f[now][2] = max_(f[now][2], f[now][1] + f[v][1] + node(ed[i].val, -1));
        tmp = f[now][1];
        for (int j = 0; j < 3; ++j) f[now][1] = max_(f[now][1], tmp + f[v][j]);
        f[now][1] = max_(f[now][1], f[now][0] + f[v][0] + node(ed[i].val, 1));
        f[now][1] = max_(f[now][1], f[now][0] + f[v][1] + node(ed[i].val, 0));
        tmp = f[now][0];
        for (int j = 0; j < 3; ++j) f[now][0] = max_(f[now][0], tmp + f[v][j]);
    }
}

inline int read() {
    register int s = 0, f = 1; register char ch = getchar();
    while (!isdigit(ch)) f = (ch == '-' ? -1 : 1), ch = getchar();
    while (isdigit(ch)) s = (s * 10) + (ch & 15), ch = getchar();
    return s * f;
}

int n, k;

int main() {
    n = read(); k = read(); ++k;
    for (int i = 1, u, v, w; i < n; ++i) {
        u = read(); v = read(); w = read();
        addedge(u, v, w); addedge(v, u, w);
    } ll L = -1e12, R = 1e12;
    while (L <= R) {
        C = (L + R + inf) / 2ll - inf / 2ll;
        dfs(1, 0); node p = max_(f[1][0], max_(f[1][1], f[1][2]));
        if (p.k == k) {
            printf("%lld\n", p.v);
            return 0;
        }
        if (p.k < k) L = C + 1;
        else R = C - 1;
    } dfs(1, 0); node p = max_(f[1][0], max_(f[1][1], f[1][2]));
    printf("%lld\n", p.v);
    return 0;
}

by Kyo1337 @ 2023-05-01 10:54:34

有没有一种可能,当二分到 mid 时切点在 k,二分到 mid + 1 时切点在 k + 2


|