\(\color{#0066ff}{ 题目描述 }\)

这个世界有 n 个城市,这 n 个城市被恰好 \(n-1\) 条双向道路联通,即任意两个城市都可以 互相到达。同时城市 1 坐落在世界的中心,占领了这个城市就称霸了这个世界。

在最开始,这 n 个城市都不在任何国家的控制之下,但是随着社会的发展,一些城市会崛 起形成国家并夺取世界的霸权。为了方便,我们标记第 i 个城市崛起产生的国家为第 i 个国家。 在第 i 个城市崛起的过程中,第 i 个国家会取得城市 i 到城市 1 路径上所有城市的控制权。

新的城市的崛起往往意味着战争与死亡,若第 i 个国家在崛起中,需要取得一个原本被国 家 \(j(j≠i)\) 控制的城市的控制权,那么国家 i 就必须向国家 j 宣战并进行战争。

现在,可怜知道了,在历史上,第 i 个城市一共崛起了 \(a_i\) 次。但是这些事件发生的相对顺 序已经无从考究了,唯一的信息是,在一个城市崛起称霸世界之前,新的城市是不会崛起的。

战争对人民来说是灾难性的。可怜定义一次崛起的灾难度为崛起的过程中会和多少不同的国家进行战争(和同一个国家进行多次战争只会被计入一次)。可怜想要知道,在所有可能的崛 起顺序中,灾难度之和最大是多少。

同时,在考古学家的努力下,越来越多的历史资料被发掘了出来,根据这些新的资料,可怜会对 \(a_i\) 进行一些修正。具体来说,可怜会对\(a_i\) 进行一些操作,每次会将 \(a_x\) 加上 w。她希望 在每次修改之后,都能计算得到最大的灾难度。

然而可怜对复杂的计算并不感兴趣,因此她想让你来帮她计算一下这些数值。 对题面的一些补充:

  • 同一个城市多次崛起形成的国家是同一个国家,这意味着同一个城市连续崛起两次是不会 和任何国家开战的:因为这些城市原来就在它的控制之下。
  • 在历史的演变过程中,第 i 个国家可能会有一段时间没有任何城市的控制权。但是这并不 意味着第 i 个国家灭亡了,在城市 i 崛起的时候,第 i 个国家仍然会取得 1 到 i 路径上的城市的控制权。

\(\color{#0066ff}{输入格式}\)

第一行输入两个整数 n,m 表示城市个数和操作个数。

第二行输入 n 个整数表示 ai 的初始值。 接下来 n − 1 行,每行输入两个整数 \(u_i, v_i\)(\(1\leq ui, vi \leq n\)) 描述了一条道路。

接下来 m 行每行输入两个整数 \(x_i\), \(w_i\) 表示将 \(a_{x_i}\) 加上 \(w_i\)。

\(\color{#0066ff}{输出格式}\)

输出共 \(m+1\) 行,第一行表示初始的 ai 的答案,接下来 m 行每行表示这次修正后的答案。

\(\color{#0066ff}{输入样例}\)

5 3
1 1 1 1 1
1 2
1 3
2 4
2 5
2 1
3 1
4 1

\(\color{#0066ff}{输出样例}\)

6
7
9
10

\(\color{#0066ff}{数据范围与提示}\)

在修正开始之前,如果按照所在城市 4, 1, 5, 3, 2 的顺序崛起,那么依次会和 0, 1, 2, 1, 2 个 国家进行战争。

这时一共会产生 6 对敌对关系。可以证明这是所有崛起顺序中的最大值。

\(\color{#0066ff}{ 题解 }\)

简单来说,题意就是给你每个点可以access的次数,还有修改,让你找到最优的access的顺序,使得虚实变换的次数最多

考虑每个点的子树。假设已经对所有子树中的点构造出了一个最优顺序(一个序列),那么一定不会和它的所有祖先的子树中的最优序列产生冲突。

所以我们考虑一个点x,能对x的实子边产生影响的,是x的所有子树和x本身(access(x)后x无实子边)

每次切换会对ans有1的贡献,显然同一子树的影响是相同的

因此我们让不同的子树或x交替进行access,这样产生的贡献才最多

当没有某棵子树的a之和或者x的a过大时,可以构造出(除了第一次)每个access都用贡献的方案

反之,当总和大于所有子树总和的一半时,就不行了,a之和特别大的那个子树(或x)一定有几次access是没有贡献的,设S为子树a之和,c为x的每棵子树,则贡献为

\[ \min\{S_x-1,2*(S_x-\max\{a_x,\forall S_c\})\} \]

这样DP就能把不带修改的分拿到了

现在考虑修改

首先,对于x的a加上w,只会对x到根的路径上的节点产生影响

因为我们只是加上一个值,所以如果某些子树的a之和大于一半,把a带进去发现贡献是不变的

某个子树的a之和大于总和一半???这是树剖的轻重边划分啊

所以如果某个子树的a之和大于总和一半,就连重边,否则就是轻边

于是我们在全局保存一个ans,access的时候找到虚边,直接减去原来的贡献,然后用w进行修改, 判断是否要切换虚实边,并让ans加上新的贡献即可

可以设一个type表示当前点是哪个类型(某子树极大,自己极大,都不怎么大)

#include<bits/stdc++.h>
#define LL long long
LL in() {char ch; LL x = 0, f = 1;while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));return x * f;
}
const int maxn = 4e5 + 10;
struct node {node *ch[2], *fa;LL tp, a, tot, siz;//维护子树a之和,siz记录虚子树的东西,tot是总共的和node(LL tp = 0, LL a = 0, LL tot = 0, LL siz = 0): tp(tp), a(a), tot(tot), siz(siz) {}void upd() {tot = siz + a;if(ch[0]) tot += ch[0]->tot;if(ch[1]) tot += ch[1]->tot;}bool ntr() { return fa && (fa->ch[0] == this || fa->ch[1] == this); }bool isr() { return fa->ch[1] == this; }
}pool[maxn];
struct EDGE {int to;EDGE *nxt;EDGE(int to = 0, EDGE *nxt = NULL): to(to), nxt(nxt) {}
}*head[maxn];
void add(int from, int to) {head[from] = new EDGE(to, head[from]);
}
void rot(node *x) {node *y = x->fa, *z = y->fa;bool k = x->isr(); node *w = x->ch[!k];if(y->ntr()) z->ch[y->isr()] = x;(x->ch[!k] = y)->ch[k] = w;(y->fa = x)->fa = z;if(w) w->fa = y;y->upd(), x->upd();
}
void splay(node *o) {while(o->ntr()) {if(o->fa->ntr()) rot(o->isr() ^ o->fa->isr()? o : o->fa);rot(o); }
}
int n, m;
LL ans;
void dfs(node *x, node *fa) {   //初始的ansnode *pos = x;LL max = x->a;for(EDGE *i = head[x - pool]; i; i = i->nxt) {node *y = pool + i->to;if(y == fa) continue;dfs(y, x);y->fa = x;x->siz += y->tot;   //刚开始都是虚边if(max < y->tot) max = y->tot, pos = y; //找到max用来DP}if(max << 1 > (x->tot = x->siz + x->a)) {   //取后面ans += (x->tot - max) << 1;if(x != pos) x->siz -= (x->ch[1] = pos)->tot; //子树大,连实边else x->tp = 1;          //自己大}else x->tp = 2, ans += x->tot - 1; //取前面
}
void access(node *x, LL w) {for(node *y = NULL; x; x = (y = x)->fa) {splay(x);LL sum = x->tot - (x->ch[0]? x->ch[0]->tot : 0); //sum是原来子树的a之和(子树肯定比自己深度大,所以减去左子树)//减去原来的贡献,通过type来搞if(x->tp < 2) {if(x->tp) ans -= (sum - x->a) << 1;else ans -= (sum - (x->ch[1]? x->ch[1]->tot : 0)) << 1;}else ans -= sum - 1;sum += w, x->tot += w; //进行修改if(y) x->siz += w;else x->a += w;if(y && (y->tot << 1) > sum) {   //是否应该改变实边所向if(x->ch[1]) x->siz += x->ch[1]->tot;x->siz -= (x->ch[1] = y)->tot;}if(x->ch[1] && (x->ch[1]->tot << 1) > sum) {  //统计新贡献x->tp = 0;ans += (sum - x->ch[1]->tot) << 1;}else {if(x->ch[1]) x->siz += x->ch[1]->tot, x->ch[1] = NULL;if((x->a << 1) > sum) x->tp = 1, ans += (sum - x->a) << 1;else x->tp = 2, ans += (sum - 1), x->ch[1] = 0;}}
}int main() {n = in(), m = in();int x, y;for(int i = 1; i <= n; i++) pool[i].a = in();for(int i = 1; i < n; i++) x = in(), y = in(), add(x, y), add(y, x);dfs(pool + 1, pool), printf("%lld\n", ans);while(m --> 0) x = in(), y = in(), access(pool + x, y), printf("%lld\n", ans);return 0;
}

转载于:https://www.cnblogs.com/olinr/p/10402115.html

P4338 [ZJOI2018]历史 LCT+树形DP相关推荐

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

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

  2. Luogu4338 ZJOI2018 历史 LCT、贪心

    传送门 题意:在$N$个点的$LCT$中,最开始每条边的虚实不定,给出每一个点的$access$次数,求一种$access$方案使得每条边的虚实变换次数之和最大,需要支持动态增加某个点的$access ...

  3. 洛谷.4383.[八省联考2018]林克卡特树lct(树形DP 带权二分)

    题目链接 \(Description\) 给定一棵边带权的树.求删掉K条边.再连上K条权为0的边后,新树的最大直径. \(n,K\leq3\times10^5\). \(Solution\) 题目可以 ...

  4. P4383 [八省联考2018]林克卡特树lct 树形DP+凸优化/带权二分

    $ \color{#0066ff}{ 题目描述 }$ 小L 最近沉迷于塞尔达传说:荒野之息(The Legend of Zelda: Breath of The Wild)无法自拔,他尤其喜欢游戏中的 ...

  5. P4338 [ZJOI2018]历史(树剖)(暴力)

    前言 有点懊恼的一个题- 并没有其他那些ZJOI那么毒瘤,看出了关键结论,但最后维护卡在log条虚边的伞兵性质上了. 解析 第一眼:感觉根本不可做啊. 冷静一下,既然它还变态的带修,一定是可以转化成比 ...

  6. [LCT动态树] [NOI2014]魔法森林,[ZJOI2018]历史

    [NOI2014] 魔法森林 题目 按照aaa精灵从小到大排序 按顺序插入每一条边 加入第iii条边后的最小代价为a[i]a[i]a[i]加上从111到nnn的所有路径中最大bbb最小的路径代价 维护 ...

  7. BNUOJ 52305 Around the World 树形dp

    题目链接: https://www.bnuoj.com/v3/problem_show.php?pid=52305 Around the World Time Limit: 20000msMemory ...

  8. [树形dp] Jzoj P5233 概率博弈

    Description 小A和小B在玩游戏.这个游戏是这样的: 有一棵n个点的以1为根的有根树,叶子有权值.假设有m个叶子,那么树上每个叶子的权值序列就是一个1->m 的排列. 一开始在1号点有 ...

  9. fwt优化+树形DP HDU 5909

    1 //fwt优化+树形DP HDU 5909 2 //见官方题解 3 // BestCoder Round #88 http://bestcoder.hdu.edu.cn/ 4 5 #include ...

最新文章

  1. oracle 11g 大小,修改oracle 11GR2归档模式和归档目录及大小-Oracle
  2. java path设置错误_linux下环境变量PATH设置错误的补救
  3. Fashion-MNIST数据集离线加载办法
  4. 检查电脑是否被安装***三个小命令
  5. 1、css引入的方式有哪些?_发泡机的原理都有哪些呢?
  6. mysql 准则 杂谈
  7. 微型计算机釆用,计算机硬件选择题及答案.docx
  8. 力扣-56 合并区间
  9. Sentry的安装搭建与使用
  10. 去除 火狐浏览器自动给域名前加 www.
  11. 兄弟HL-1118加粉清零
  12. 下载sqlserver2012 试用_有哪些可以免费试用的电商ERP?
  13. php7isapi,如何选择PHP套件中ISAPI和FastCGI模式的版本?_护卫神
  14. PDF模板查找关键字坐标
  15. 从汇编的角度理解什么是引用
  16. angularjs textarea 剩余字数统计
  17. 性能测试模型-曲线拐点模型-压力曲线分析图
  18. 随机池化(Stochastic Pooling)
  19. 综合布线方案设计模版
  20. 详解酒店IPTV系统 -- -南京邮电大学 江凌云

热门文章

  1. react18-学习笔记36-组件库起航 第一个组件需求分析
  2. 小红书怎么运营推广?小红书运营推广流程介绍
  3. 高云FPGA系列教程(5):ARM点灯工程设计
  4. Acrobat Pro DC 2020 Mac使用教程
  5. 如何利用快解析软件搭建映射端口
  6. VC++实现全局钩子勾住textout金山快译的原理实现
  7. 曾鸣:智能商业,是决胜未来30年的新商业思维
  8. 两种登录方式的信息显示
  9. android设备登录工行卡,工行Android手机银行怎么登陆?
  10. 安全合规--47--基于国内法律法规的企业数据合规体系建设经验总结(五)