\(\mathscr{Description}\)

  Link.

  给定一棵以 \(1\) 为根的树,点 \(u\) 有非负点权 \(a_u\)。

  定义 \(u\) 的一次染色的代价为:路径 \(u\rightarrow 1\) 上染有的不为 \(u\) 的颜色种类,并把该路径上的所有结点颜色染为 \(u\)。

  定义一棵树的染色代价为:初始时所有结点无色,以任意顺序对结点进行染色操作,使得结点 \(u\) 恰好被操作 \(a_u\) 次,能得到的最大操作代价和。

  给出 \(m\) 次操作,每次给定 \(u,k\),\(k>0\),令 \(a_u\leftarrow a_u+k\)。每次修改后求出这棵树的染色代价。

  \(n,m\le4\times10^5\)。

\(\mathscr{Solution}\)

  惯用 trick:染色时的颜色冲突一定可以在 LCA 处不重不漏地统计。对于 \(u\),设其子树内的 \(a\) 之和为 \(s\),自己的权值以及孩子子树和的最大值为 \(x\),显然 \(u\) 处最多冲突

\[f(s,x)=\begin{cases}
s-1,&2x\le s\\
2(s-x),&2x>s
\end{cases}
\]

次,而 \(\sum_u f(s_u,x_u)\) 就是答案。

  奇妙的观察:修改的 \(k>0\),因此修改若在 \(u\) 的最大值子树内且 \(2x_u>s_u\),则一定不会导致 \(f(s_u,x_u)\) 改变。

  因此,可以 LCT 动态维护树形,\(u\) 与其原树孩子 \(v\) 是实边当且仅当 \(2s_u>s_v\)。注意这样的规定虽然导致我们完全不能 access,但是每遇到一条虚边,子树和 \(\times 2\),故任意结点到根的虚边数量恒不超过 \(\mathcal O(\log V)\)。修改时,转一转 splay,讨论一下每条虚边的取舍即可。

  虚边访问次数是 \(\mathcal O(q\log V)\),但 splay 内部是否能套用 LCT 的均摊证明其复杂度呢?或者说有什么巧妙的证明方法呢?求教 qwq。

\(\mathscr{Code}\)

/*+Rainybunny+*/

#include <bits/stdc++.h>

#define rep(i, l, r) for (int i = l, rep##i = r; i <= rep##i; ++i)
#define per(i, r, l) for (int i = r, per##i = l; i >= per##i; --i)
#ifndef RYBY
# undef assert
# define assert(expr) // do nothing.
#endif typedef long long LL; inline char fgc() {
static char buf[1 << 17], *p = buf, *q = buf;
return p == q && (q = buf + fread(p = buf, 1, 1 << 17, stdin), p == q) ?
EOF : *p++;
} template <typename Tp = int>
inline Tp rint() {
Tp x = 0, s = fgc(), f = 1;
for (; s < '0' || '9' < s; s = fgc()) f = s == '-' ? -f : f;
for (; '0' <= s && s <= '9'; s = fgc()) x = x * 10 + (s ^ '0');
return x * f;
} template <typename Tp>
inline void wint(Tp x) {
if (x < 0) putchar('-'), x = -x;
if (9 < x) wint(x / 10);
putchar(x % 10 ^ '0');
} const int MAXN = 4e5;
int n, m, ecnt, head[MAXN + 5];
struct Edge { int to, nxt; } graph[MAXN * 2 + 5];
LL ans; inline void link(const int u, const int v) {
graph[++ecnt] = { v, head[u] }, head[u] = ecnt;
graph[++ecnt] = { u, head[v] }, head[v] = ecnt;
} struct LinkCutTree {
int fa[MAXN + 5], ch[MAXN + 5][2];
LL val[MAXN + 5], asum[MAXN + 5], vsum[MAXN + 5]; inline bool nroot(const int u) {
return ch[fa[u]][0] == u || ch[fa[u]][1] == u;
} inline void pushup(const int u) {
asum[u] = asum[ch[u][0]] + asum[ch[u][1]] + val[u] + vsum[u];
} inline LL contr(const int u) {
assert(!nroot(u));
LL s = asum[u] - asum[ch[u][0]];
if (ch[u][1]) {
// assert(asum[ch[u][1]] << 1 > s);
return s - asum[ch[u][1]] << 1;
}
if (val[u] << 1 > s) return s - val[u] << 1;
return s - 1;
} inline void init(const int u) { // specialized.
int mx = u; asum[u] = val[u];
for (int i = head[u], v; i; i = graph[i].nxt) {
if ((v = graph[i].to) != fa[u]) {
fa[v] = u, init(v), vsum[u] += asum[v];
if (asum[v] > asum[mx]) mx = v;
}
}
asum[u] += vsum[u];
if (mx != u && asum[mx] << 1 > asum[u]) {
ch[u][1] = mx, vsum[u] -= asum[mx];
}
ans += contr(u);
} inline void rotate(const int u) {
int v = fa[u], w = fa[v], k = ch[v][1] == u;
fa[u] = w; if (nroot(v)) ch[w][ch[w][1] == v] = u;
if ((ch[v][k] = ch[u][!k])) fa[ch[v][k]] = v;
pushup(ch[fa[v] = u][!k] = v), pushup(u);
} inline void splay(const int u) {
for (int v; nroot(u); rotate(u)) {
if (nroot(v = fa[u])) {
rotate(u ^ v ^ ch[v][0] ^ ch[fa[v]][0] ? u : v);
}
}
} inline void update(const int u, const int k) { // semi-access.
for (int v = u; v; v = fa[v]) {
splay(v), ans -= contr(v);
asum[v] += k, (u == v ? val[v] : vsum[v]) += k;
}
if (asum[ch[u][1]] << 1 <= asum[u] - asum[ch[u][0]]) {
vsum[u] += asum[ch[u][1]], ch[u][1] = 0;
}
ans += contr(u);
for (int v = u, w; (w = fa[v]); v = w) {
LL s = asum[w] - asum[ch[w][0]];
if (asum[ch[w][1]] << 1 <= s) {
vsum[w] += asum[ch[w][1]], ch[w][1] = 0;
}
if (asum[v] << 1 > s) {
vsum[w] -= asum[v], ch[w][1] = v;
}
ans += contr(w);
}
}
} lct; int main() {
n = rint(), m = rint();
rep (i, 1, n) lct.val[i] = rint();
rep (i, 2, n) link(rint(), rint()); lct.init(1);
wint(ans), putchar('\n');
for (int u, k; m--;) {
u = rint(), k = rint();
lct.update(u, k);
wint(ans), putchar('\n');
}
return 0;
}

Solution -「ZJOI 2018」「洛谷 P4338」历史的更多相关文章

  1. 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)

    洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...

  2. 「区间DP」「洛谷P1043」数字游戏

    「洛谷P1043」数字游戏 日后再写 代码 /*#!/bin/sh dir=$GEDIT_CURRENT_DOCUMENT_DIR name=$GEDIT_CURRENT_DOCUMENT_NAME ...

  3. Solution -「JSOI 2019」「洛谷 P5334」节日庆典

    \(\mathscr{Description}\)   Link.   给定字符串 \(S\),求 \(S\) 的每个前缀的最小表示法起始下标(若有多个,取最小的).   \(|S|\le3\time ...

  4. Solution -「洛谷 P4372」Out of Sorts P

    \(\mathcal{Description}\)   OurOJ & 洛谷 P4372(几乎一致)   设计一个排序算法,设现在对 \(\{a_n\}\) 中 \([l,r]\) 内的元素排 ...

  5. Solution -「POI 2010」「洛谷 P3511」MOS-Bridges

    \(\mathcal{Description}\)   Link.(洛谷上这翻译真的一言难尽呐.   给定一个 \(n\) 个点 \(m\) 条边的无向图,一条边 \((u,v,a,b)\) 表示从 ...

  6. Solution -「APIO 2016」「洛谷 P3643」划艇

    \(\mathcal{Description}\)   Link & 双倍经验.   给定 \(n\) 个区间 \([a_i,b_i)\)(注意原题是闭区间,这里只为方便后文描述),求 \(\ ...

  7. 「洛谷4197」「BZOJ3545」peak【线段树合并】

    题目链接 [洛谷] [BZOJ]没有权限号嘤嘤嘤.题号:3545 题解 窝不会克鲁斯卡尔重构树怎么办??? 可以离线乱搞. 我们将所有的操作全都存下来. 为了解决小于等于\(x\)的操作,那么我们按照 ...

  8. 「洛谷3338」「ZJOI2014」力【FFT】

    题目链接 [BZOJ] [洛谷] 题解 首先我们需要对这个式子进行化简,否则对着这么大一坨东西只能暴力... \[F_i=\sum_{j<i} \frac{q_iq_j}{(i-j)^2}-\s ...

  9. 「BZOJ2733」「洛谷3224」「HNOI2012」永无乡【线段树合并】

    题目链接 [洛谷] 题解 很明显是要用线段树合并的. 对于当前的每一个连通块都建立一个权值线段树. 权值线段树处理操作中的\(k\)大的问题. 如果需要合并,那么就线段树暴力合并,时间复杂度是\(nl ...

  10. 「洛谷3870」「TJOI2009」开关【线段树】

    题目链接 [洛谷] 题解 来做一下水题来掩饰ZJOI2019考炸的心情QwQ. 很明显可以线段树. 维护两个值,\(Lazy\)懒标记表示当前区间是否需要翻转,\(s\)表示区间还有多少灯是亮着的. ...

随机推荐

  1. Graphische Datenverarbeitung Ⅰ 学习笔记

    1. Pipeline 1.1 Graphische Primitive 1.2 Model and View Transform 1.3 Vertex Shading 1.4 Clipping 1. ...

  2. 5.1 Vim及其安装

    通过前面的学习我们知道,Linux 系统中"一切皆文件",因此当我们在命令行下更改文件内容时,不可避免地要用到文本编辑器. 作为一名 Linux 初学者,你必须熟练掌握 Linux ...

  3. 本地文件包含漏洞详解与CTF实战

    1. 本地文件包含简介 1.1 本地文件包含定义 本地文件包含是一种Web应用程序漏洞,攻击者通过操控文件路径参数,使得服务器端包含了非预期的文件,从而可能导致敏感信息泄露. 常见的攻击方式包括: 包 ...

  4. 【一步步开发AI运动小程序】十六、AI运动识别中,如何判断人体站位?

    [云智AI运动识别小程序插件],可以为您的小程序,赋于人体检测识别.运动检测识别.姿态识别检测AI能力.本地原生识别引擎,无需依赖任何后台或第三方服务,有着识别速度快.体验佳.扩展性强.集成快.成本低 ...

  5. 女友用python写的充值卡冲话费的代码

    女友最近在学习python ,于是我拿当初我们学习C语言的课程设计 手机号充话费功能让她尝试着做一下,在分析完思路和帮助改错的情况下代码如下: python2.7.17 环境 #/usr/bin/py ...

  6. 万字长文带你深入Redis底层数据结构

    Redis数据库的数据结构 Redis 的键值对中的 key 就是字符串对象,而 value 就是指Redis的数据类型,可以是String,也可以是List.Hash.Set. Zset 的数据类型 ...

  7. Java 并发编程实战学习笔记——路径查找类型并行任务的终止

    1.该类问题的递归串行算法(深度优先遍历) 代码 复制 - 运行 package net.jcip.examples; import java.util.*; /** * SequentialPuzz ...

  8. laravel之任务调度(定时任务)

    crontab指令线性增长.毕竟crontab是一项系统级的配置,在业务中我们为了节约机器,往往对于量不大的多个项目会放在同一台服务器上,crontab指令多了就容易管理混乱,并且功能也不够灵活强大( ...

  9. AmplifyImpostors源码阅读

    首先看一下点击Bake按钮后的执行流程: 1.AmplifyImpostorInspector部分 首先点击按钮设置了bakeTexture = true if( GUILayout.Button( ...

  10. Git clone报错“Connection was reset, errno 10054”

    前情 最近在使用一个UI库的时候,发现其中一个BUG,于是想尝试提一个PR. 坑位 我平时习惯用https的方式拉取代码,发现在clone代码的时候一直失败,错误提示:OpenSSL SSL_read ...