洛谷 P9047 [PA2021] Poborcy podatkowi
阅读原文时间:2023年08月14日阅读:1

给一棵有边权的树,从中选出若干条长度为 4 的路径,要求边不交,求最大权值和。

数据范围:\(1\le n\le 2\times 10^5, -10^9\le w\le 10^9\)。

考虑朴素平方做法:设 \(f_{i, 0/1/2/3}\) 表示 \(i\) 的子树内的答案,同时记录 \(i\) 上可能有的一条不完整路径的长度。在每个点处合并儿子,注意到具体谁和谁拼接不太重要,进行一个 DP,记录当前长度为 2 路径的奇偶性,以及长度为 1,3 路径的个数差,就可以做到 \(n^2\)。瓶颈在于长度 1,3 的路径的拼接。

一个结论:数轴上从原点开始随机游走,每次等概率左右移动,最终到达的最远的点到原点的距离期望是根号级别。考虑随机打乱儿子,那么对于最优解的 DP 路径,长度 1,3 路径的个数差始终在儿子个数的平方根的几倍以内的概率非常大,那么我们 DP 数组只开这么大,得到答案多半也是对的。这样,时间复杂度优化为 \(\Theta(n\sqrt{n})\)。

// Author: kyEEcccccc

#include <bits/stdc++.h>

using namespace std;

using LL = long long;
using ULL = unsigned long long;

#define F(i, l, r) for (int i = (l); i <= (r); ++i)
#define FF(i, r, l) for (int i = (r); i >= (l); --i)
#define MAX(a, b) ((a) = max(a, b))
#define MIN(a, b) ((a) = min(a, b))
#define SZ(a) ((int)((a).size()) - 1)

const int N = 200005, B = 1000;

int n;
vector<pair<int, LL>> e[N];
mt19937 ran(chrono::system_clock::now().time_since_epoch().count());
LL f[N][4], g[2][B * 2 + 5][2];

void dp(int u, int par, LL wp)
{
    for (auto pi : e[u])
    {
        if (pi.first == par) continue;
        dp(pi.first, u, pi.second);
    }
    int pre_i = 0, cur_i = 1;
    memset(g, 0xc0, sizeof (g));
    g[0][B + 1][0] = 0;
    for (auto pi : e[u])
    {
        if (pi.first == par) continue;
        int v = pi.first;
        F(i, 1, B * 2 + 1) F(t, 0, 1)
        {
            MAX(g[cur_i][i][t], g[pre_i][i][t ^ 1] + f[v][2]);
            MAX(g[cur_i][i][t], g[pre_i][i - 1][t] + f[v][1]);
            MAX(g[cur_i][i][t], g[pre_i][i + 1][t] + f[v][3]);
            MAX(g[cur_i][i][t], g[pre_i][i][t] + f[v][0]);
        }
        swap(pre_i, cur_i);
    }
    MAX(f[u][0], g[pre_i][B + 1][0]);
    MAX(f[u][0], g[pre_i][B][0] + wp);
    MAX(f[u][1], g[pre_i][B + 1][0] + wp);
    MAX(f[u][2], g[pre_i][B + 2][0] + wp);
    MAX(f[u][3], g[pre_i][B + 1][1] + wp);
}

signed main(void)
{
    // freopen(".in", "r", stdin);
    // freopen(".out", "w", stdout);
    ios::sync_with_stdio(0), cin.tie(nullptr);

    cin >> n;
    F(i, 1, n - 1)
    {
        int u, v; LL w; cin >> u >> v >> w;
        e[u].emplace_back(v, w); e[v].emplace_back(u, w);
    }
    F(u, 1, n) shuffle(e[u].begin(), e[u].end(), ran);
    memset(f, 0xc0, sizeof (f));
    dp(1, 0, LLONG_MIN / 2);
    cout << f[1][0] << endl;

    return 0;
}

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器