「ZJOI2018」历史

前置知识

\(\text{LCT}\) 维护子树信息,考虑辅助树上一个节点的子树信息只是其代表的这一段链的信息,设 \(S(u)\) 为节点 \(u\) 的子树信息,那么在辅助树上我们维护的是:

\[S(u)=S(lson)+S(rson)+val(u)
\]

考虑它们的实际意义 \(lson\) 是 \(u\) 的父亲,\(rson\) 是 \(u\) 的重儿子,显然 \(S(lson)\) 是我们不需要的,而真正的辅助信息只算了节点本身和重儿子。

考虑按照这样算的话, \(u\) 的每一个轻儿子代表的子树信息都是合法的,那么可以再开一个 \(vs(u)\) 把所有轻儿子的 \(S\) 加上去。

\[S(u)=S(lson)+S(rson)+val(u)+vs(u)
\]

轻重链切换的时候暴力更新一下 \(vs(u)\) 即可,动态加边的话因为要影响虚边,要把两个点都 \(\text{makeroot}\) 来保证更新的 \(vs(u)\) 合法,删边的话因为保证了关系是重儿子,所以直接做就好了,\(access\) 切换轻重边的时候需要重新维护一下。

但这种做法适用范围不大,信息不可减就做不了,只能单点不断条重链修改,然而对这道题来说已经足够了。

解题思路

观察发现每个节点的贡献是独立的,同一个儿子内的连续多次崛起不会贡献新的代价。显然要最大化每个节点的贡献需要尽可能两次崛起位于不同的儿子的子树。

设节点 \(u\) 的子树 \(a_i\) 和为 \(sz(u)\) ,\(mson=\max(\max_{u\rightarrow v}sz(v), a(u))\) 。

如果 \(2mson\leq sz(u)\) ,那么显然可以构造出操作序列满足不会有连续相同,贡献就是 \(sz(u)-1\)。

否则可以贪心的考虑,尽可能多用 \(mson\) ,节点 \(u\) 的贡献就是 \(2(sz(u)-mson)\)。

如果 \(u\) 的一个儿子 \(v\) 满足 \(2sz(v)>sz(u)\) ,那么我们记 \(u\rightarrow v\) 这条边为重边,其余边为轻边,类似于树链剖分和 \(\text{LCT}\) 的结构。

然后我们可以得到一些基本推论。

  1. 一个节点向下只会至多有一条重边。
  2. 一个节点到根的路径上只会至多有 \(log_{na_i}\) 条轻边,因为每有一条轻边 \(sz(u)\) 至少减少二分之一。

观察发现每一次修改操作,路径上的重边仍旧是重边,所以贡献不变,路径上的轻边可能会发生改变,只需要找到这些轻边暴力改就好了。

前面说了这个结构和 \(\text{LCT}\) 很类似,只需要每条重链用辅助树维护,支持单点加求一个点在根为 \(1\) 时的子树和,以及找一个点到一条路径上的轻边。

前面两个要求 \(\text{LCT}\) 维护子树信息可以直接做,查询只需要类似 \(access\) 走一遍,但是不要强制断开原有的重边,而是对于每条轻边按照前置知识的方法更新子树和再判断,细节有点多。

复杂度的话,单次修改 \(\text{splay}\) 重链条数次,轻边条数是 \(O(log_{na_i})\) ,和正常的 \(\text{LCT}\) 没啥区别,套用那个的均摊分析就是 \(\mathcal O(nlogn)\) 。

code

/*program by mangoyang*/
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
}
const int N = 800005;
vector<int> g[N];
int ch[N][2], fa[N], n, m;
ll vs[N], a[N], s[N], ans;
#define son(x) (ch[fa[x]][1] == x)
#define isr(x) (ch[fa[x]][0] != x && ch[fa[x]][1] != x)
inline void update(int u){ s[u] = s[ch[u][0]] + s[ch[u][1]] + a[u] + vs[u]; }
inline void rotate(int x){
int F = fa[x], G = fa[F], w = son(x);
if(!isr(F)) ch[G][son(F)] = x; fa[x] = G;
ch[F][w] = ch[x][w^1], fa[ch[x][w^1]] = F;
ch[x][w^1] = F, fa[F] = x, update(F);
}
inline void splay(int x){
for(int F = fa[x]; !isr(x); rotate(x), F = fa[x])
if(!isr(F)) rotate(son(F) == son(x) ? F : x);
update(x);
}
inline ll calc(int x, ll t, ll h){
return ch[x][1] ? ((t - h) << 1) : ((a[x] << 1) > t ? ((t - a[x]) << 1) : t - 1);
}
inline void access(int x, int w){
splay(x);
ll now = s[x] - s[ch[x][0]], mson = s[ch[x][1]];
ans -= calc(x, now, mson), s[x] += w, a[x] += w, now += w;
if((mson << 1) <= now) vs[x] += mson, ch[x][1] = mson = 0;
ans += calc(x, now, mson), update(x);
int c = x; x = fa[x];
for(; x; c = x, x = fa[x]){
splay(x);
ll now = s[x] - s[ch[x][0]], mson = s[ch[x][1]];
ans -= calc(x, now, mson), s[x] += w, vs[x] += w, now += w;
if((mson << 1) <= now) vs[x] += mson, ch[x][1] = mson = 0;
if((s[c] << 1) > now) vs[x] -= (mson = s[c]), ch[x][1] = c;
ans += calc(x, now, mson), update(x);
}
}
inline void dfs(int u){
s[u] = a[u];
for(int i = 0; i < (int) g[u].size(); i++)
if(g[u][i] != fa[u]) fa[g[u][i]] = u, dfs(g[u][i]), s[u] += s[g[u][i]];
for(int i = 0; i < (int) g[u].size(); i++)
if(g[u][i] != fa[u] && s[g[u][i]] * 2 > s[u]) ch[u][1] = g[u][i];
vs[u] = s[u] - a[u] - s[ch[u][1]];
ans += calc(u, s[u], s[ch[u][1]]);
}
int main(){
read(n), read(m);
for(int i = 1; i <= n; i++) read(a[i]);
for(int i = 1, x, y; i < n; i++){
read(x), read(y);
g[x].push_back(y), g[y].push_back(x);
}
dfs(1);
printf("%lld\n", ans);
for(int i = 1, x, y; i <= m; i++){
read(x), read(y), access(x, y);
printf("%lld\n", ans);
}
return 0;
}

「ZJOI2018」历史的更多相关文章

  1. 「ZJOI2018」历史(LCT)

    「ZJOI2018」历史(LCT) \(ZJOI\) 也就数据结构可做了-- 题意:给定每个点 \(access\) 次数,使轻重链切换次数最大,带修改. \(30pts:\) 挺好想的.发现切换次数 ...

  2. @loj - 2434@ 「ZJOI2018」历史

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 九条可怜是一个热爱阅读的女孩子. 这段时间,她看了一本非常有趣的 ...

  3. 题解 「ZJOI2018」历史

    题目传送门 Description 九条可怜是一个热爱阅读的女孩子. 这段时间,她看了一本非常有趣的小说,这本小说的架空世界引起了她的兴趣. 这个世界有 \(n\) 个城市,这 \(n\) 个城市被恰 ...

  4. LOJ #2434. 「ZJOI2018」历史(LCT)

    题意 click here 题解 我们首先考虑答案是个什么样的东西, 不难 发现每个点可以单独计算它的贡献. 令每个点 \(i\) 崛起次数为 \(a_i\) . 假设一个点子树的 \(\sum a_ ...

  5. LOJ2434. 「ZJOI2018」历史 [LCT]

    LOJ 思路 第一眼看似乎没有什么思路,试着套个DP上去:设\(dp_x\)表示只考虑\(x\)子树,能得到的最大答案. 合并的时候发现只有\(x\)这个点有可能做出新的贡献,而做出新贡献的时候必然是 ...

  6. 「ZJOI2018」胖(ST表+二分)

    「ZJOI2018」胖(ST表+二分) 不开 \(O_2\) 又没卡过去是种怎么体验... 这可能是 \(ZJOI2018\) 最简单的一题了...我都能 \(A\)... 首先我们发现这个奇怪的图每 ...

  7. Loj #2529. 「ZJOI2018」胖

    Loj #2529. 「ZJOI2018」胖 题目描述 Cedyks 是九条可怜的好朋友(可能这场比赛公开以后就不是了),也是这题的主人公. Cedyks 是一个富有的男孩子.他住在著名的 The P ...

  8. 「JOISC 2014 Day1」 历史研究

    「JOISC 2014 Day1」 历史研究 Solution 子任务2 暴力,用\(cnt\)记录每种权值出现次数. 子任务3 这不是一个尺取吗... 然后用multiset维护当前的区间,动态加, ...

  9. 「2014-2-26」Unicode vs. UTF-8 etc.

    目测是个老问题了.随便一搜,网上各种总结过.这里不辞啰嗦,尽量简洁的备忘一下. 几个链接,有道云笔记链接,都是知乎上几个问题的摘录:阮一峰的日志,1-5 还是值得参考,但是之后的部分则混淆了 Wind ...

随机推荐

  1. CSS中filter滤镜的学习笔记

    1.CSS静态滤镜样式 (filter)(只有IE4.0以上支持)  CSS静态滤镜样式的使用方法:{ filter : filtername( parameters1, parameters2, . ...

  2. 图片异或(xor)getflag

    题目地址:https://files.cnblogs.com/files/nul1/flag_enc.png.tar 这题是源于:网鼎杯minified 经过测试隧道红色最低通道异常.其余均正常.所以 ...

  3. linux下C语言实现多线程通信—环形缓冲区,可用于生产者(producer)/消费者(consumer)【转】

    转自:http://blog.chinaunix.net/uid-28458801-id-4262445.html 操作系统:ubuntu10.04 前言:     在嵌入式开发中,只要是带操作系统的 ...

  4. Minimum Palindromic Factorization(最少回文串分割)

    Minimum Palindromic Factorization(最少回文串分割) 以下内容大部分(可以说除了关于回文树的部分)来自论文A Subquadratic Algorithm for Mi ...

  5. 如何使用curl命令指定ip访问url

    有时我们需要测试一个url,但域名并没解析,这时为了一个简单的测试而写host或去做域名解析,显然这并不高效,而有些域名甚至是正式的域名,因此我们可有使用curl命令进行测试 方法一 curl url ...

  6. 8.Python3标准库--数据持久存储与交换

    ''' 持久存储数据以便长期使用包括两个方面:在对象的内存中表示和存储格式之间来回转换数据,以及处理转换后数据的存储区. 标准库包含很多模块可以处理不同情况下的这两个方面 有两个模块可以将对象转换为一 ...

  7. 学习笔记----float后不与前面元素同行解决办法。

    <li>文本<span> 16-08-17</span></li> 当非float的元素和float的元素在一起的时候(如上代码), 如果非float元 ...

  8. poj 2828(线段树单点更新)

    Buy Tickets Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 18561   Accepted: 9209 Desc ...

  9. Java Character & String & Scanner类

    Character类 Character 类用于对单个字符进行操作. Character 类在对象中包装一个基本类型 char 的值 char用法: char ch = 'a'; // Unicode ...

  10. 791. Custom Sort String

    S and T are strings composed of lowercase letters. In S, no letter occurs more than once. S was sort ...