Luogu4338 ZJOI2018 历史 LCT、贪心
题意:在$N$个点的$LCT$中,最开始每条边的虚实不定,给出每一个点的$access$次数,求一种$access$方案使得每条边的虚实变换次数之和最大,需要支持动态增加某个点的$access$次数。$N \leq 4 \times 10^5$
ZJOI2018真的都是大火题
首先一个小小的转化:对于每个非叶子节点,新开一个叶子节点,将当前非叶子节点的$access$次数转移到这些叶子节点上,这样所有的$access$操作都在叶子节点进行,可以少很多的判断。
接着我们需要考虑在每一个点上最大化方案总数。因为必须相邻两次$access$由不同子树的叶子节点发起才能够贡献$1$的答案,而我们希望每一次$access$都能尽可能多贡献答案,所以尽可能让相邻两次$access$来自不同子树。考虑树上某一个非叶子节点$x$,其所有儿子为集合$i$,$S$表示子树$access$次数总和,显然答案贡献的最大值与$\sum S_i$与$max\{S_i\}$相关,因为当$max\{S_i\}$占$\sum S_i$比例特别大的时候,则必定要有很多同一子树来的$access$操作被放在一起。
现讲结论吧,最大$access$贡献是
$$min\{S_i-1 , 2 \times (\sum S_i - max \{S_i\})\}$$
也就是在$max\{S_i\} > \frac{\sum S_i + 1}{2}$时总贡献数量会取右边一项
$min$中的左边一项表示的是任意两个$access$之间都产生$1$的贡献(最优的情况),而对于右边的项,因为只有取到最大值的子树的贡献次数变少了,那么我们考虑所有其他子树,它们每一次$access$都可以在这一次$access$的之前、之后的$access$中取到$2$的贡献,所以贡献总和就是右边那一项,树形$DP$计算一次就能获得$30pts$。
接着我们考虑修改操作。如果在某一个点的子树集合$i$上存在一个子树$x$满足$S_x > \frac{\sum S_i + 1}{2}$,那么如果我们在子树$x$上加上$access$次数$w$,和和最大值同时增加了$w$,也就是说贡献没有变化。我们考虑将满足$S_x > \frac{\sum S_i + 1}{2}$的点与其父亲连一条实边,表示这一条边连接的两个点之间无需转移,而其他的边就连为轻边。
观察一下条件:$S_x > \frac{\sum S_i + 1}{2}$,是不是很像重链剖分?其实实质就是重链剖分
然后我们就只需要考虑轻边上的转移了。可以知道每一个点到根的轻边的数量是$log \, \sum (access \text{次数})$级别的,复杂度也符合要求。所以可以使用$LCT$动态维护轻重边的划分,外部计算全局答案,每一次找到一条轻边的时候,看能否将其改为重边,去掉以前这个点的贡献,加上当前的贡献即可。
#include<bits/stdc++.h>
#define int long long
#define lch Tree[x].ch[0]
#define rch Tree[x].ch[1]
#define mid ((Tree[x].sum + 1) >> 1)
//This code is written by Itst
using namespace std; inline int read(){
int a = ;
bool f = ;
char c = getchar();
while(c != EOF && !isdigit(c)){
if(c == '-')
f = ;
c = getchar();
}
while(c != EOF && isdigit(c)){
a = (a << ) + (a << ) + (c ^ '');
c = getchar();
}
return f ? -a : a;
} const int MAXN = ;
struct node{
int fa , ch[] , sum , non_sum;
bool type;
}Tree[MAXN << ];
struct Edge{
int end , upEd;
}Ed[MAXN << ];
int a[MAXN] , head[MAXN] , sum , N , cntEd; inline bool nroot(int x){
return Tree[Tree[x].fa].ch[] == x || Tree[Tree[x].fa].ch[] == x;
} inline bool son(int x){
return Tree[Tree[x].fa].ch[] == x;
} inline void pushup(int x){
Tree[x].sum = Tree[lch].sum + Tree[rch].sum + Tree[x].non_sum + (x > N ? a[x - N] : );
} inline void rotate(int x){
bool f = son(x);
int y = Tree[x].fa , z = Tree[y].fa , w = Tree[x].ch[f ^ ];
if(nroot(y))
Tree[z].ch[son(y)] = x;
Tree[x].fa = z;
Tree[x].ch[f ^ ] = y;
Tree[y].fa = x;
Tree[y].ch[f] = w;
if(w)
Tree[w].fa = y;
pushup(y);
} inline void Splay(int x){
while(nroot(x)){
if(nroot(Tree[x].fa))
rotate(son(x) == son(Tree[x].fa) ? Tree[x].fa : x);
rotate(x);
}
pushup(x);
} inline void access(int x , int w){
a[x - N] += w;
Splay(x);
while(Tree[x].fa){
Splay(Tree[x].fa);
int k = Tree[x].fa , t = Tree[k].sum - Tree[Tree[k].ch[]].sum;
if(Tree[k].ch[])
sum -= (t - Tree[Tree[k].ch[]].sum) << ;
else
sum -= t - ;
Tree[k].non_sum += w;
Tree[k].sum += w;
t += w;
if(Tree[Tree[k].ch[]].sum < Tree[x].sum){
Tree[k].non_sum = Tree[k].non_sum - Tree[x].sum + Tree[Tree[k].ch[]].sum;
Tree[k].ch[] = x;
}
if(((t + ) >> ) < Tree[Tree[k].ch[]].sum)
sum += (t - Tree[Tree[k].ch[]].sum) << ;
else{
sum += t - ;
Tree[k].non_sum += Tree[Tree[k].ch[]].sum;
Tree[k].ch[] = ;
}
x = k;
}
} inline void addEd(int a , int b){
Ed[++cntEd].end = b;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
} void dfs(int x , int fa){
Tree[x].fa = fa;
if(x > N)
return;
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != fa){
dfs(Ed[i].end , x);
Tree[x].sum += Tree[Ed[i].end].sum;
}
for(int i = head[x] ; i ; i = Ed[i].upEd)
if(Ed[i].end != fa && mid < Tree[Ed[i].end].sum){
sum += (Tree[x].sum - Tree[Ed[i].end].sum) << ;
Tree[x].non_sum = Tree[x].sum - Tree[Ed[i].end].sum;
Tree[x].ch[] = Ed[i].end;
return;
}
sum += Tree[x].sum - ;
Tree[x].non_sum = Tree[x].sum;
} signed main(){
#ifndef ONLINE_JUDGE
freopen("4338.in" , "r" , stdin);
//freopen("4338.out" , "w" , stdout);
#endif
N = read();
int M = read();
for(int i = ; i <= N ; ++i)
Tree[i + N].sum = a[i] = read();
for(int i = ; i < N ; ++i){
int a = read() , b = read();
addEd(a , b);
addEd(b , a);
}
for(int i = ; i <= N ; ++i)
addEd(i , i + N);
dfs( , );
printf("%lld\n" , sum);
while(M--){
int a = read() , x = read();
access(a + N , x);
printf("%lld\n" , sum);
}
return ;
}
Luogu4338 ZJOI2018 历史 LCT、贪心的更多相关文章
- P4338 [ZJOI2018]历史 LCT+树形DP
\(\color{#0066ff}{ 题目描述 }\) 这个世界有 n 个城市,这 n 个城市被恰好 \(n-1\) 条双向道路联通,即任意两个城市都可以 互相到达.同时城市 1 坐落在世界的中心,占 ...
- [ZJOI2018]历史
[ZJOI2018]历史 最大化access轻重链的切换次数 考虑一个点的贡献,即它交换重儿子的次数 发现这个次数只和它自己ai以及每个儿子的子树次数和有关. 一个关键的事实是: 我们可以自上而下进行 ...
- 【BZOJ5212】[ZJOI2018]历史(Link-Cut Tree)
[BZOJ5212][ZJOI2018]历史(Link-Cut Tree) 题面 洛谷 BZOJ 题解 显然实际上就是给定了一棵树和每个点被\(access\)的次数,求解轻重链切换的最大次数. 先考 ...
- [ZJOI2018]历史(LCT)
这篇还发了洛谷题解 [Luogu4338] [BZOJ5212] 题解 题意 给出一棵树,给定每一个点的 \(access\) 次数,计算轻重链切换次数的最大值,带修改. 先考虑不带修改怎么做 假设 ...
- 洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)
洛谷题目传送门 ZJOI的考场上最弱外省选手T2 10分成功滚粗...... 首先要想到30分的结论 说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点 想到了又有什么用? ...
- BZOJ5212 ZJOI2018历史(LCT)
首先相当于最大化access的轻重边交换次数. 考虑每个点作为战场(而不是每个点所代表的国家与其他国家交战)对答案的贡献,显然每次产生贡献都是该点的子树内(包括自身)此次access的点与上次acce ...
- 【BZOJ5212】[ZJOI2018] 历史(LCT大黑题)
点此看题面 大致题意: 给定一棵树每个节点\(Access\)的次数,求最大虚实链切换次数,带修改. 什么是\(Access\)? 推荐你先去学一学\(LCT\)吧. 初始化(不带修改的做法) 首先考 ...
- LOJ2434. 「ZJOI2018」历史 [LCT]
LOJ 思路 第一眼看似乎没有什么思路,试着套个DP上去:设\(dp_x\)表示只考虑\(x\)子树,能得到的最大答案. 合并的时候发现只有\(x\)这个点有可能做出新的贡献,而做出新贡献的时候必然是 ...
- bzoj 5212: [Zjoi2018]历史
Description 九条可怜是一个热爱阅读的女孩子. 这段时间,她看了一本非常有趣的小说,这本小说的架空世界引起了她的兴趣. 这个世界有n个城市,这n个城市被恰好n?1条双向道路联通,即任意两个城 ...
随机推荐
- vue.js及项目实战[笔记]— 01 vue.js
一. vue基础 1. 历史介绍 angular 09年,年份较早,一开始大家是拒绝的 react 2013年,用户体验较好,直接拉到一堆粉丝 vue 2014年,用户体验较好 前端框架与库的区别 j ...
- ActiveReports公开课开启报名,学习如何解决中国式复杂报表难题
ActiveReports实战教学 90分钟解决中国式复杂报表六大需求 [开课时间]4月19日 [主讲老师]葡萄城资深报表专家 [培训方式]网络在线公开课 报名地址
- 使用Twitter异常检测框架遇到的坑
在Github上搜索“Anomaly Detection”,Twitter的异常检测框架(基于R语言)高居榜首,可见效果应该不错: 但是活跃度并不高,3-4年没人维护了: 因此在使用时难免会遇到一些坑 ...
- IDEA错误:Failed to start end point associated with ProtocolHandler [http-nio-9999] java.net.BindException: Address already in use: bind
日志显示进程端口已被占用,首先需要的是查询什么进程占用了当前的9999端口. 1.win+R输入cmd进入命令界面: 2.输入命令 netstat -ano|findstr "端口号&qu ...
- 一. Redis 常用命令
键值相关命令 1. KETS 查询所有的key 127.0.0.1:6379> keys * 1) "tony"2) "hexu1"3) "he ...
- 简述 Spring Cloud 是什么2
一.概念定义 Spring Cloud是一个微服务框架,相比Dubbo等RPC框架, Spring Cloud提供的全套的分布式系统解决方案. Spring Cloud对微服务基础框架Ne ...
- npm与yarn常用命令对比
最近在用yarn,但是命令老是记不住,在此记录,方便日后翻看 图片截取自:http://yuanhehe.cn/2017/06/11/npm-%E4%B8%8E-Yarn-%E5%B8%B8%E7%9 ...
- sql 语句查询 sqlserver 数据库 MAC 地址
declare @dbid int set @dbid=db_id('dbName') select distinct hostname, db_name(dbid), net_address, lo ...
- Centos7.5.1804永久生效修改主机名
原来主机名 [root@node1 ~]# 查看Centos的版本: [root@node1 ~]# cat /etc/redhat-release CentOS Linux release (Cor ...
- MySql数据库基础笔记(一)
一.表与库的概念 数据库管理数据,它是以什么样的形式组成的? 生活中的表---->表 table多行多列,传统的数据库都是这样的;声明了表头,一个表创建好了,剩下的就是往表中添加数据 多张表放在 ...