[题解]我才是 Joker

\[\color{red}{\text{校长者,真神人也,左马桶,右永神,会执利笔破邪炁,何人当之?}} \\ \begin{array}{|} \hline \color{pink}{\text{The principal is really a god}} \\ \color{pink}{\text{with a closestool on the left and Yongshen on the right}} \\ \color{pink}{\text{holding a sharp pen to pierce the truth}} \\ \color{pink}{\text{Who can resist him? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{green}{\text{校長は本当に神であり、左側にトイレ、右側にヨンシェンがあり}} \\ \color{green}{\text{鋭いペンを持って真実を突き刺している。誰が彼に抵抗できるだろうか? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{lightblue}{\text{Le principal est vraiment un dieu}} \\ \color{lightblue}{\text{avec des toilettes à gauche et Yongshen à droite}} \\ \color{lightblue}{\text{tenant un stylo pointu pour percer la vérité}} \\ \color{lightblue}{\text{Qui peut lui résister ? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{purple}{\text{Der Direktor ist wirklich ein Gott}} \\ \color{purple}{\text{mit einer Toilette links und Yongshen rechts}} \\ \color{purple}{\text{der einen spitzen Stift hält}} \\ \color{purple}{\text{um die Wahrheit zu durchdringen.}} \\ \color{purple}{\text{Wer kann ihm widerstehen? }} \\ \hline \end{array} \\ \begin{array}{|} \hline \color{cyan}{\text{Principalis deus est, Yongshen a dextris cum latrina}} \\ \color{cyan}{\text{acuto stylo ad perforandum veritatem: quis resistet ei? }} \\ \hline \end{array} \\ \color{red}{\text{对曰:“无人,狗欲当之,还请赐教!”}} \\ \newcommand\brak[1]{\left({#1}\right)} \newcommand\Brak[1]{\left\{{#1}\right\}} \newcommand\d[0]{\text{d}} \newcommand\string[2]{\genfrac{\{}{\}}{0pt}{}{#1}{#2}} \newcommand\down[2]{{#1}^{\underline{#2}}} \newcommand\ddiv[2]{\left\lfloor\frac{#1}{#2}\right\rfloor} \newcommand\udiv[2]{\left\lceil\frac{#1}{#2}\right\rceil} \newcommand\lcm[0]{\operatorname{lcm}} \newcommand\set[1]{\left\{{#1}\right\}} \newcommand\ceil[1]{\left\lceil{#1}\right\rceil} \newcommand\floor[1]{\left\lfloor{#1}\right\rfloor} \newcommand\rhs[1]{\;\text{Rhs}\;#1} \newcommand\lhs[1]{\;\text{Lhs}\;#1} \newcommand\Vec[1]{\vec{\mathbf{#1}}} \newcommand\rank[0]{\text{rank}} \]

  \(\mathcal{Back\;To\;The\;Menu}\).

2022-03-15 我才是 Joker

  真没想到 T1 的 \(\mathcal O(n^5)\) 跑得这么快,预估是可能在常数上有一个 \(\displaystyle \frac{1}{16}\) 的缘故。另外 T3 还没有补,着实想不通了。

梦批糼 / Dream

  我也不会念这个题目的名字。

  其实我们的目标就是算出包含每个格子的合法的长方体的个数,最暴力的方法是 \(\mathcal O(n^9)\),花费 \(\mathcal O(n^6)\) 代价枚举矩形,再用 \(\mathcal O(n^3)\) 枚举矩形中每一个元素算贡献。这种方法用高维前缀和优化就可以降为 \(\mathcal O(n^6)\),还是有点距离。

  如果我们将枚举的目标换成一个点,显然也不好,因为基础复杂度就是 \(\mathcal O(n^3)\),再加上一些统计的实现,可能就变成 \(\mathcal O(n^6)\) ,但是,如果我们将枚举一个点变成枚举一个面?显然基础复杂度是 \(\mathcal O(n^4)\) 的,但是我们只需要 \(\mathcal O(n)\) 去扫一遍这个面所对应的所有合法的极长柱就行了,对于极长柱的每一层,用一个差分来 \(\mathcal O(1)\) 记录答案即可。

  因此总复杂度是 \(\mathcal O(n^5)\) 的,但是常数上有一个 \(\displaystyle \frac{1}{4}\),这可能也是它可以过的原因。

/** @author __Elaina__ */

// #pragma GCC optimize("Ofast")

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {;
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

#define int long long

const int Maxn = 60;
const int mod = 998244353;
inline void chkadd(int& x, int y) { if ((x += y) >= mod) x -= mod; }

inline int qkpow(int a, int q) {
    int p = 1;
    for (; q; q >>= 1, a = 1ll * a * a % mod)
        if (q & 1) p = 1ll * p * a % mod;
    return p;
}

int n, m, r, q, u;
int cnt[Maxn + 5][Maxn + 5][Maxn + 5];
int val[Maxn + 5][Maxn + 5][Maxn + 5];

inline void input() {
    readin(n, m, r, q);
    u = (1ll * n * (n + 1) * m * (m + 1) * r * (r + 1) / 8) % mod;
    rep (i, 1, n) rep (j, 1, m) rep (k, 1, r)
        readin(cnt[i][j][k]), cnt[i][j][k] ^= 1;
    rep (i, 1, n) rep (j, 1, m) rep (k, 1, r)
        readin(val[i][j][k]);
}

inline void prelude() {
    rep (k, 1, r) rep (i, 1, n) rep (j, 1, m)
        cnt[i][j][k] += cnt[i - 1][j][k] + cnt[i][j - 1][k] - cnt[i - 1][j - 1][k];
}

int buc[Maxn + 5];
int ans[Maxn + 5][Maxn + 5][Maxn + 5], valid = 0;
inline void solve() {
    rep (lx, 1, n) rep (rx, lx, n) rep (ly, 1, m) rep (ry, ly, m) {
        rep (i, 1, r) buc[i] = cnt[rx][ry][i]
          - cnt[lx - 1][ry][i] - cnt[rx][ly - 1][i]
          + cnt[lx - 1][ly - 1][i];
        // masdf("Now lx == %d, rx == %d, ly == %d, ry == %d\n", lx, rx, ly, ry);
        for (int i = 1, j = 1; i <= r; i = ++j) if (!buc[i]) {
            while (j < r && !buc[j + 1]) ++j;
            valid += (j - i + 1) * (j - i + 2) >> 1;
            rep (k, i, j) {
                int x = (k - i + 1) * (j - k + 1);
                ans[lx][ly][k] += x;
                ans[rx + 1][ly][k] -= x;
                ans[lx][ry + 1][k] -= x;
                ans[rx + 1][ry + 1][k] += x;
            }
        }
    }
    rep (k, 1, r) rep (i, 1, n) rep (j, 1, m)
        ans[i][j][k] += ans[i - 1][j][k] + ans[i][j - 1][k] - ans[i - 1][j - 1][k];
}

inline void calc() {
    int res = 0, sum;
    sum = qkpow(1ll * valid * qkpow(u, mod - 2) % mod, q);
    valid = qkpow(valid, mod - 2);
    rep (i, 1, n) rep (j, 1, m) rep (k, 1, r) {
        int p = (1 + mod - qkpow((1 + mod - 1ll * ans[i][j][k] * valid % mod) % mod, q)) % mod;
        p = 1ll * p * sum % mod;
        chkadd(res, 1ll * p * val[i][j][k] % mod);
    }
    writln(res);
}

signed main() {
    freopen("dream.in", "r", stdin);
    freopen("dream.out", "w", stdout);
    input();
    prelude();
    solve();
    calc();
    return 0;
}

等你哈苏德 / Wait

  并不明白题目的意思。

  区间覆盖并不需要关注整个数列,实际上我们只需要考察端点的情况就行了,换而言之,先转成前缀的情况,然后再关注每个端点的情况即可。在此基础上,注意到 "使得数轴上对于每个点,覆盖他的黑区间个数和白区间个数差的绝对值小于等于 1",这引导我们向欧拉路方面考虑,因为欧拉路满足这条路上每个点的入度与出度之差小于等于 1,刚好和这道题匹配。

  离散化后,我们只需要关心每个端点处的差值。如果把区间 \([l, r]\) 视为 \(l\)\(r\) 之间连了一条无向边,染色视作是定向,我们可以发现这就是一个欧拉路径问题。我们把奇度数的点排序后依次连接,跑欧拉回路即可。

  一部分线段染色相当于是混合图欧拉回路,跑网络流即可。由于这是个单位流量的图,所以 Dinic 算法可以快速跑出。

/** @author __Elaina__ */

// #pragma GCC optimize("Ofast")

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {;
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 6e4;
const int Maxm = 1e6;

int m, n;
int l[Maxn + 5], r[Maxn + 5], w[Maxn + 5];
map<int, int> id;

int S, T, ncnt;
struct edge { int to, nxt, f; } e[Maxm << 1 | 1];
int tail[Maxn + 5], ecnt, cur[Maxn + 5];
inline void update(int i, int flow) { e[i].f -= flow, e[i ^ 1].f += flow; }
inline void add_edge(int u, int v, int f) {
    e[ecnt] = edge{v, tail[u], f}; tail[u] = ecnt++;
    e[ecnt] = edge{u, tail[v], 0}; tail[v] = ecnt++;
}

int prit[Maxn + 5], deg[Maxn + 5];
int corres[Maxn + 5];

int que[Maxn + 5], tl, hd;
int dis[Maxn + 5];
inline bool bfs() {
    memset(dis + 1, 0x3f, ncnt << 2);
    que[hd = tl = 1] = S, dis[S] = 0;
    for (int u = que[hd]; hd++ <= tl; u = que[hd]) {
        for (int i = tail[u], v; ~i; i = e[i].nxt) if (e[i].f) {
            if (dis[v = e[i].to] == 0x3f3f3f3f) que[++tl] = v, dis[v] = dis[u] + 1;
        }
    }
    return dis[T] != 0x3f3f3f3f;
}
int dfs(int u, int flow) {
    if (u == T) return flow;
    int used = 0, v;
    for (int& i = cur[u]; ~i; i = e[i].nxt) if (e[i].f) {
        if (dis[v = e[i].to] == dis[u] + 1) {
            int ret = dfs(v, min(flow - used, e[i].f));
            update(i, ret), used += ret;
            if (used == flow) break;
        }
    }
    return used;
}
inline int dinic() {
    int mxf = 0;
    while (bfs()) {
        memcpy(cur + 1, tail + 1, ncnt << 2);
        mxf += dfs(S, 0x3f3f3f3f);
    }
    return mxf;
}

signed main() {
    // freopen("wait.in", "r", stdin);
    // freopen("wait.out", "w", stdout);
    readin(m, n), n = 0;
    rep (i, 1, m) {
        readin(l[i], r[i], w[i]), ++r[i];
        id[l[i]] = id[r[i]] = 1;
    }
    for (auto& it: id) it.se = ++n;
    ncnt = n;
    S = ++ncnt, T = ++ncnt;
    rep (i, 1, m) {
        l[i] = id[l[i]], r[i] = id[r[i]];
        prit[l[i]] ^= 1, prit[r[i]] ^= 1;
    }
    memset(tail, 0xff, sizeof tail);
    mt19937 rnd((unsigned)time(NULL));
    rep (i, 1, n) if (prit[i]) {
        if (i == n) return puts("-1"), 0;
        prit[i] ^= 1, prit[i + 1] ^= 1;
        int t = rnd() & 1; // randomly orient the edge
        ++deg[i + t], --deg[i + (t ^ 1)];
        add_edge(i + t, i + (t ^ 1), 1);
    }
    rep (i, 1, m) {
        if (w[i] == 0) ++deg[l[i]], --deg[r[i]];
        else if (w[i] == 1) ++deg[r[i]], --deg[l[i]];
        else if (rnd() & 1) {
            w[i] = 1;
            ++deg[r[i]], --deg[l[i]];
            corres[i] = ecnt;
            add_edge(r[i], l[i], 1);
        }
        else {
            w[i] = 0;
            ++deg[l[i]], --deg[r[i]];
            corres[i] = ecnt;
            add_edge(l[i], r[i], 1);
        }
    }
    int mxf = 0;
    rep (i, 1, n) if (deg[i] != 0) {
        if (deg[i] > 0) add_edge(S, i, deg[i] >> 1), mxf += deg[i] >> 1;
        else add_edge(i, T, (-deg[i]) >> 1);
    }
    int res = dinic();
    if (res ^ mxf) return puts("-1"), 0;
    rep (i, 1, m) {
        if (corres[i] && e[corres[i] ^ 1].f) w[i] ^= 1;
        writln(w[i], " \n"[i == m]);
    }
    return 0;
}

喜欢最最痛 / Love

  答案分成两个部分:对于一个 \(K\)\(dp_i\) 表示加 \(i\) 条额外边且 必须走 的代价,和前 \(K\) 个加边代价中的前 \(i\) 小和。而 必须走这 \(i\) 条边林克卡特树 中也有体现 —— 实际上就是在这个树上选 \(i\) 条边不相交的链使得权值最大。

  因此我们可以使用树形 DP 解决在树上选择 \(i\) 条最大权的边不交的链。时间复杂度为 \(\mathcal O(n^2)\)\(\mathcal O(nm)\)

int siz[Maxn + 5];
void dfs1(int u, int par) {
    siz[u] = 1;
    for (const auto& [v, w]: g[u]) if (v ^ par)
        dfs1(v, u), siz[u] += siz[v];
}
ll f[Maxn + 5][Maxn + 5][2];
ll tmp[Maxn + 5][2];
void dfs2(int u, int par) {
    f[u][0][0] = 0;
    for (const auto& [v, w]: g[u]) if (v ^ par) {
        dfs2(v, u);
        for (int i = 0; i <= siz[u]; ++i)
            tie(tmp[i][0], tmp[i][1]) = tie(f[u][i][0], f[u][i][1]);
        for (int i = 0; i <= siz[u]; ++i) {
            for (int j = 0; j <= siz[v]; ++j) {
                chkmax(tmp[i + j][0], f[u][i][0] + f[v][j][0]);
                chkmax(tmp[i + j][1], f[u][i][1] + f[v][j][0]);
                chkmax(tmp[i + j][1], f[u][i][0] + f[v][j][1] + w);
                chkmax(tmp[i + j][1], f[u][i][0] + f[v][j][0] + w);
                chkmax(tmp[i + j + 1][0], f[u][i][1] + f[v][j][1] + w);
                chkmax(tmp[i + j + 1][0], f[u][i][1] + f[v][j][0] + w);
                chkmax(tmp[i + j + 1][0], f[u][i][0] + f[v][j][0] + w);
                chkmax(tmp[i + j + 1][1], f[u][i][1] + f[v][j][0] + w);
                chkmax(tmp[i + j + 1][1], f[u][i][0] + f[v][j][1] + w);
            }
        }
        for (int i = 0; i <= siz[u]; ++i)
            tie(f[u][i][0], f[u][i][1]) = tie(tmp[i][0], tmp[i][1]);
    }
    rep (j, 0, siz[u])
        chkmax(f[u][j + 1][0], f[u][j][1]);
    // rep (j, 0, siz[u]) {
    //     masdf("f[%d, %d, %d] == %lld\n", u, j, 0, f[u][j][0]);
    //     masdf("f[%d, %d, %d] == %lld\n", u, j, 1, f[u][j][1]);
    // }
}

  考虑优化选择 \(i\) 条不交且权值最大的链的过程,考虑使用与费用流类似的 悔过 操作,每次在这棵树上找直径,然后将直径的边翻转成负的。因为有负权边,所以考虑选择 LCT 或者树剖维护 DDP 来实现,时间复杂度应当为 \(\mathcal O(n\log n)\sim \mathcal O(n\log^2 n)\).

  至于对于一个 \(K\) 应当如何计算答案,注意到 \(dp_i\) 是两个凸函数相加 —— 选择链的函数是斜率单减的,加额外边的函数是斜率单增的,因此我们可以在平衡树上二分出这个答案。

  具体地,我们需要在树剖上维护一个点的直径,以及该区间的符号被整体翻转之后(填上负号)的直径,然后其他情况用类似线段树维护线段最值的方法即可,需要讨论的东西有点多,需要 仔细一点......代码实现用的全局平衡二叉树,因此复杂度是 \(\mathcal O(n\log n)\) 的。

/** @author __Elaina__ */

#pragma GCC optimize("O2")

#include <bits/stdc++.h>
using namespace std;

#define USING_FREAD
// #define NDEBUG
#include <cassert>

namespace Elaina {
/** その可憐な少女は魔女であり、旅人でした。 ―― そう、私です! */

#define rep(i, l, r) for(int i = (l), i##_end_ = (r); i <= i##_end_; ++i)
#define repf(i, l, r) for (int i = (l), i##_end_ = (r); i < i##_end_; ++i)
#define drep(i, l, r) for(int i = (l), i##_end_ = (r); i >= i##_end_; --i)
#define fi first
#define se second
#define mp(a, b) make_pair(a, b)
#define Endl putchar('\n')
#define whole(v) ((v).begin()), ((v).end())
#define bitcnt(s) (__builtin_popcount(s))
/** @warning no forced type conversion */
#define rqr(x) ((x) * (x))
#define y0 FUCK_UP
#define y1 MOTHER_FUCKER
#define masdf(...) fprintf(stderr, __VA_ARGS__)

typedef long long ll;
typedef unsigned long long ull;
typedef std::pair<int, int> pii;
typedef vector<int> vset;

template<class T> inline T fab(T x) { return x < 0 ? -x : x; }
template<class T> inline void chkmin(T& x, const T rhs) { x = std::min(x, rhs); }
template<class T> inline void chkmax(T& x, const T rhs) { x = std::max(x, rhs); }

#ifdef USING_FREAD
inline char qkgetc() {
# define BUFFERSIZE 1 << 20
    static char BUF[BUFFERSIZE], *p1 = BUF, *p2 = BUF;
    return p1 == p2 && (p2 = (p1 = BUF) + fread(BUF, 1, BUFFERSIZE, stdin), p1 == p2) ? EOF : *p1++;
# undef BUFFERSIZE
}
# define CHARRECEI qkgetc()
#else
# define CHARRECEI getchar()
#endif

template<class T> inline T readret(T x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if(c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    return f ? -x : x;
}
template<class T> inline void readin(T& x) {
    x = 0; int f = 0; char c;
    while (!isdigit(c = CHARRECEI)) if (c == '-') f = 1;
    for (x = (c ^ 48); isdigit(c = CHARRECEI); x = (x << 1) + (x << 3) + (c ^ 48));
    if (f) x = -x;
}
template<class T, class... Args> inline void readin(T& x, Args&... args) {
    readin(x), readin(args...);
}
template<class T> inline void writln(T x, char c = '\n') {
    if (x < 0) putchar('-'), x = -x;
    static int __stk[55], __bit = 0;
    do __stk[++__bit] = x % 10, x /= 10; while (x);
    while (__bit) putchar(__stk[__bit--] ^ 48);
    putchar(c);
}
template<class T> inline T listMax(const T& x) { return x; }
template<class T, class... Args> inline T listMax(const T& x, const Args&... args) {
    return max(x, listMax(args...));
}
template<class T> inline T listMin(const T& x) { return x; }
template<class T, class... Args> inline T listMin(const T& x, const Args&... args) {
    return min(x, listMin(args...));
}

} // namespace Elaina
using namespace Elaina;

const int Maxn = 1e5 * 3; // third times: threeDeglization & turning edge to nodes
const ll inf = 0x3f3f3f3f3f3f3f3f;

int n, m; ll sum;
ll cost[Maxn + 5];

struct edge { int to, nxt; } e[Maxn * 2 + 5];
int tail[Maxn + 5], ecnt, ncnt;
ll val[Maxn + 5]; // the value of the node
inline void link(int u, int v) {
    e[ecnt] = edge{v, tail[u]}; tail[u] = ecnt++;
    e[ecnt] = edge{u, tail[v]}; tail[v] = ecnt++;
}

inline void input() {
    readin(n, m), ncnt = n;
    memset(tail, 0xff, sizeof tail);
    int u, v, w;
    rep (i, 2, n) {
        readin(u, v, w), sum += w << 1;
        val[++ncnt] = w; // turn edge to node
        link(u, ncnt), link(ncnt, v);
    }
    rep (i, 1, m) readin(cost[i]);
}


/** <-------------------------  ThreeDeglization  -------------------------> */
vset g[Maxn + 5];
inline void add_edge(int u, int v) {
    g[u].push_back(v), g[v].push_back(u);
}
void rebuild(int u, int par) {
    vset son;
    for (int i = tail[u], v; ~i; i = e[i].nxt) if ((v = e[i].to) != par)
        rebuild(v, u), son.push_back(v);
    if (son.size() < 3) {
        for (const int& v: son) add_edge(u, v);
    } else {
        int len = son.size() - 2; // apply the node [ncnt + 1, ncnt + len]
        repf (i, ncnt + 1, ncnt + len) add_edge(i, i + 1);
        add_edge(u, son[0]), add_edge(u, ncnt + 1);
        add_edge(ncnt + len, son.back()), son.pop_back();
        repf (i, 1, son.size()) add_edge(ncnt + i, son[i]);
        ncnt += len;
    }
}


/** <-------------------------  The Preparation for Building The GBBT - Part1  ------------------------->*/
int siz[Maxn + 5], wson[Maxn + 5], fa[Maxn + 5], dep[Maxn + 5];
int tp[Maxn + 5], dfn[Maxn + 5], id[Maxn + 5], tl[Maxn + 5], rt[Maxn + 5];
void dfs1(int u, int par) {
    siz[u] = 1, fa[u] = par, dep[u] = dep[par] + 1;
    for (const int& v: g[u]) if (v ^ par) {
        dfs1(v, u), siz[u] += siz[v];
        if (siz[v] > siz[wson[u]]) wson[u] = v;
    }
}


/** <-------------------------  Globally Balanced Binary Tree  -------------------------> */
struct chain {
    int u, v; ll d;   // u is the shallower one
    inline bool operator <(const chain& rhs) const {
        if (d != rhs.d) return d < rhs.d;
        else return u == rhs.u? v < rhs.v: u < rhs.u;
    }
};
struct node {
    int ls, rs;
    int l, r;                     // the interval
    ll val, sum;                  // the value and sum of the subtree
    chain tol[2], tor[2], mxx[2]; // the to-left chain & to-right chain, and the max length of the cahin
    int tag;                      // reverse tag
} tre[Maxn + 5];
typedef pair<int, ll> lFromChain; // light-from chain
lFromChain tolight[Maxn + 5];     // the endpos & length
chain golight[Maxn + 5];          // the longest chain when go into the subtre of light son
chain inlight[Maxn + 5];          // the longest chain in the light son
#define atls(i) tre[tre[i].ls]
#define atrs(i) tre[tre[i].rs]
inline void pushup(int i) {
    tre[i].l = tre[i].r = id[i];
    if (tre[i].ls) tre[i].l = atls(i).l;
    if (tre[i].rs) tre[i].r = atrs(i).r;
    tre[i].sum = atls(i).sum + atrs(i).sum + tre[i].val;
    for (int t = 0, sg = 1; t < 2; ++t, sg *= -1) {
        tre[i].tol[t] = listMax(
            atls(i).tol[t],
            chain{tre[i].l, atrs(i).tol[t].v, (tre[i].val + atls(i).sum) * sg + atrs(i).tol[t].d},
            chain{tre[i].l, tolight[id[i]].fi, (tre[i].val + atls(i).sum) * sg + tolight[id[i]].se}
        );
        tre[i].tor[t] = listMax(
            atrs(i).tor[t],
            chain{tre[i].r, atls(i).tor[t].v, atls(i).tor[t].d + (tre[i].val + atrs(i).sum) * sg},
            chain{tre[i].r, tolight[id[i]].fi, tolight[id[i]].se + (tre[i].val + atrs(i).sum) * sg}
        );
        tre[i].mxx[t] = listMax(
            atls(i).mxx[t],
            atrs(i).mxx[t],
            chain{atls(i).tor[t].v, tolight[id[i]].fi, atls(i).tor[t].d + tre[i].val * sg + tolight[id[i]].se},
            chain{tolight[id[i]].fi, atrs(i).tol[t].v, tre[i].val * sg + tolight[id[i]].se + atrs(i).tol[t].d},
            chain{atls(i).tor[t].v, atrs(i).tol[t].v, atls(i).tor[t].d + atrs(i).tol[t].d + tre[i].val * sg},
            inlight[id[i]]
        );
    }
}
int build(int l, int r) {
    if (l > r) return 0;
    int pivot = l, sum = 0, pre = 0;
    rep (i, l, r) sum += siz[id[i]] - siz[wson[id[i]]];
    rep (i, l, r) {
        pre += siz[id[i]] - siz[wson[id[i]]];
        if ((pre << 1) > sum) { pivot = i; break; }
    }
    tre[pivot].l = tre[pivot].r = id[pivot];
    tre[pivot].val = tre[pivot].sum = val[id[pivot]];
    tre[pivot].mxx[0] = tre[pivot].tol[0] = tre[pivot].tor[0] = chain{pivot, tolight[pivot].fi, tolight[pivot].se + val[pivot]};
    tre[pivot].mxx[1] = tre[pivot].tol[1] = tre[pivot].tor[1] = chain{pivot, tolight[pivot].fi, tolight[pivot].se - val[pivot]};
    chkmax(tre[pivot].mxx[0], inlight[pivot]);
    chkmax(tre[pivot].mxx[1], inlight[pivot]);
    tre[pivot].ls = build(l, pivot - 1);
    tre[pivot].rs = build(pivot + 1, r);
    return pushup(pivot), pivot;
}
inline void uploadInfo(int u) {
    if (u != tp[u] || !fa[u]) return ; // no fake father
    golight[fa[u]] = tre[rt[u]].tol[0];
    inlight[fa[u]] = tre[rt[u]].mxx[0];
}
inline void updateLight(int u) {
    if (!u) return ;
    tolight[u] = {u, 0};
    if (golight[u].d > tolight[u].se)
        tolight[u] = {golight[u].v, golight[u].d};
}
inline void flip(int i) {
    if (!i) return ;
    tre[i].val = -tre[i].val, tre[i].sum = -tre[i].sum;
    swap(tre[i].tol[0], tre[i].tol[1]);
    swap(tre[i].tor[0], tre[i].tor[1]);
    swap(tre[i].mxx[0], tre[i].mxx[1]);
    tre[i].tag ^= 1;
}
inline void pushdown(int i) {
    if (!tre[i].tag) return ;
    flip(tre[i].ls), flip(tre[i].rs), tre[i].tag = 0;
}
inline void modify(int i, int l, int r, int ql, int qr) {
    if (!i || ql > qr) return ;
    if (ql <= l && r <= qr) return flip(i);
    pushdown(i);
    if (ql <= i && i <= qr) tre[i].val = -tre[i].val;
    if (ql < i) modify(tre[i].ls, l, i - 1, ql, qr);
    if (i < qr) modify(tre[i].rs, i + 1, r, ql, qr);
    pushup(i);
}
inline void updateAll(int i, int to) {
    if (!i) return ;
    pushdown(i);
    if (to < i) updateAll(tre[i].ls, to);
    else if (i < to) updateAll(tre[i].rs, to);
    pushup(i);
}


/** <-------------------------  The Preparation for Building The GBBT - Part2  -------------------------> */
void dfs2(int u) {
    dfn[u] = ++*dfn, id[dfn[u]] = u, tl[tp[u]] = u;
    tolight[u] = {u, 0}, golight[u] = chain{-1, -1, 0};
    if (wson[u]) {
        tp[wson[u]] = tp[u]; dfs2(wson[u]);
        for (const int& v: g[u]) if (v ^ fa[u] && v ^ wson[u])
            dfs2(tp[v] = v);
    }
    if (u == tp[u]) {
        rt[u] = build(dfn[u], dfn[tl[u]]);
        uploadInfo(u), updateLight(fa[u]);
    }
}

inline void rever(int u, int v) {
    if (u < 1 || v < 1) return ;
    while (tp[u] ^ tp[v]) {
        if (dep[tp[u]] < dep[tp[v]]) swap(u, v);
        modify(rt[tp[u]], dfn[tp[u]], dfn[tl[tp[u]]], dfn[tp[u]], dfn[u]);
        uploadInfo(tp[u]);
        updateLight(u = fa[tp[u]]);
        updateAll(rt[tp[u]], dfn[u]);
    }
    if (dep[u] > dep[v]) swap(u, v);
    modify(rt[tp[u]], dfn[tp[u]], dfn[tl[tp[u]]], dfn[u], dfn[v]);
    while (fa[tp[u]]) {
        uploadInfo(tp[u]);
        updateLight(u = fa[tp[u]]);
        updateAll(rt[tp[u]], dfn[u]);
    }
    updateLight(tp[u]);
}

ll ans[Maxn + 5], dp[Maxn + 5];
namespace saya {

mt19937 rnd(0xcbdd1);
int son[Maxn + 5][2];
ll val[Maxn + 5], sum[Maxn + 5];
int siz[Maxn + 5];
unsigned rd[Maxn + 5];
int ncnt, rt;

inline int newnode(ll v) {
    int x = ++ncnt;
    val[x] = sum[x] = v, siz[x] = 1;
    rd[x] = ((rnd() ^ rnd() & rnd() | rnd()) & 0x7fff) << 15 | (rnd() ^ rnd() & rnd() | rnd());
    return x;
}
struct mypair {
    int c[2];
    inline int& operator [](int id) { return c[id]; }
};
inline void pushup(int x) {
    siz[x] = siz[son[x][0]] + siz[son[x][1]] + 1;
    sum[x] = sum[son[x][0]] + sum[son[x][1]] + val[x];
}
mypair split(int x, ll k) {
    if (!x) return {0, 0};
    int d = val[x] < k;
    auto ret = split(son[x][d], k);
    son[x][d] = ret[d ^ 1], ret[d ^ 1] = x;
    pushup(x);
    return ret;
}
int merge(int x, int y) {
    if (!x || !y) return x ^ y;
    int ret = 0xcbdd1;
    if (rd[x] < rd[y]) son[x][1] = merge(son[x][1], y), pushup(ret = x);
    else son[y][0] = merge(x, son[y][0]), pushup(ret = y);
    return ret;
}
inline void insert(ll k) {
    auto tmp = split(rt, k);
    rt = merge(merge(tmp[0], newnode(k)), tmp[1]);
}
inline ll query(int x, int cur) {
    if (!x) return dp[cur];
    int lsz = siz[son[x][0]] + 1;
    ll calc = val[x] + dp[cur + lsz] - dp[cur + lsz - 1];
    if (calc >= 0) return query(son[x][0], cur);
    return sum[son[x][0]] + val[x] + query(son[x][1], cur + lsz);
}

} // namespace saya

inline void solve() {
    ans[0] = dp[0] = sum;
    rep (i, 1, m) {
        chain diamet = tre[rt[1]].mxx[0];
        dp[i] = dp[i - 1] - diamet.d;
        rever(diamet.u, diamet.v);
    }
    rep (i, 1, m) {
        saya::insert(cost[i]);
        ans[i] = saya::query(saya::rt, 0);
    }
    rep (i, 0, m) writln(ans[i], " \n"[i == m]);
}

signed main() {
    freopen("love.in", "r", stdin);
    freopen("love.out", "w", stdout);
    input();
    rebuild(1, 0);
    tre[0].mxx[0] = tre[0].tol[0] = tre[0].tor[0] = chain{0, 0, -inf};
    tre[0].mxx[1] = tre[0].tol[1] = tre[0].tor[1] = chain{0, 0, -inf};
    dfs1(1, 0);
    dfs2(tp[1] = 1);
    solve();
    return 0;
}
posted @ 2022-03-15 21:25  Arextre  阅读(62)  评论(0编辑  收藏  举报