洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)
ZJOI的考场上最弱外省选手T2 10分成功滚粗。。。。。。
首先要想到30分的结论
说实话Day1前几天刚刚刚掉了SDOI2017的树点涂色,考场上也想到了这一点
想到了又有什么用?反正想不到最大的贡献是怎么推出来的
然后晚上心中怀着九条CNM看完了Solution.pdf
貌似对我这个蒟蒻来说也只有这一题可做了。。。。。。
已知书上每个点access的总次数,构造出一个顺序,最大化虚实边的切换总次数
其实如果能发现最优顺序的构造是没有后效性的话,问题便可以进一步简化
考虑每个点的子树。假设已经对所有子树中的点构造出了一个最优顺序(一个序列),那么一定不会和它的所有祖先的子树中的最优序列产生冲突。这个并不好证明,仔细想一想应该能发现。
于是就可以单独考虑每个点\(x\)。能对\(x\)的实子边产生影响的是x的所有子树和\(x\)本身(access(x)会使\(x\)没有实子边),每切换一次都会使答案\(+1\)。显然同一个子树中产生的影响是相同的。于是我们要让来自不同子树(或\(x\)本身)尽可能交替access。当没有某个子树(或\(x\)本身)的\(a\)总和过大时,可以构造出使得(除了第一次)每一次access都有贡献的方案。如果某个子树(或\(x\)本身)的\(a\)总和过大,大于所有子树总和的一半时,是不可以的,那个子树(或\(x\)本身)的某几次操作肯定不会有贡献。用数学公式大概表示每个点的贡献为(\(S\)为子树的\(a\)之和,\(c\)为\(x\)的每个子树)
\]
当\(\max\{a_x,\forall S_c\}\gt {S_x+1\over2}\)时\(\min\)取后者
用树形DP算出来就有30分了
那么怎样快速修改呢?
首先,对某个点的\(a\)加上一个值\(w\),只可能会影响该点到根的路径上的点的贡献。
因为是加一个值,所以假如这些点中某些点的子树\(S\)大于它父亲子树\(S\)的一半,那么\(S_x+w\),\(\max\{a_x,\forall S_c\}\)也会\(+w\),带入上式发现贡献是不变的!
看到某个子树S大于所有子树总和的一半,有没有想到树剖?树剖的轻重边就是这样划分的啊!(反正我这种蒟蒻就是想不到)
同样对维护好每个点子树S的树进行轻重链剖分,某些点的子树a之和大于它父亲子树a之和的一半就连重边(否则连轻边),这样每个点至多有一个重儿子。类似树剖的证明,每个点到根的轻边总数(也就是我们可能会修改的点数)是\(\log\sum a\)级别的!
修改的复杂度也有保障啦!我们只要快速找到这些点就好了。用实链剖分维护子树信息即可(应该不能叫LCT吧,没有makeroot,link和cut,对于这个问题蒟蒻的LCT总结对LCT的概念也改了改,欢迎Julao们指正!)。全局保存ans,每次进行类access操作找到虚边,就让ans直接减去以前的贡献,加上w以后判断当前的情况决定是否要切换虚实边并让ans加上新的贡献即可。
为了方便计算以前的贡献,蒟蒻觉得可以保存一下以前贡献的类型(无非就三种,某子树过大、自己过大、都不是很大)算的时候就省去了一些判断的时间。
代码细节巨多,尤其是类access更新答案那部分。所以就算考场上想到了一些东西,我这种蒟蒻也未必写得出来吧!疯狂膜拜考场切T2的laofu爷Orzzzzzzzzzzzz!
#include<cstdio>
#define RG register
#define R RG int
#define I inline void
#define lc c[x][0]
#define rc c[x][1]
#define G ch=getchar()
typedef long long L;
const int N=400009,M=N<<1;
int f[N],c[N][2],he[N],ne[M],to[M];
L ans,a[N],si[N],s[N];
short tp[N];
bool r[N];
template<typename T>
I in(RG T&x){
RG char G;
while(ch<'-')G;
x=ch&15;G;
while(ch>'-')x*=10,x+=ch&15,G;
}
inline bool nroot(R x){
return c[f[x]][0]==x||c[f[x]][1]==x;
}
I up(R x){
s[x]=s[lc]+s[rc]+si[x]+a[x];
}
I rot(R x){
R y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w;
up(f[w]=y);f[y]=x;f[x]=z;
}
I splay(R x){
R y;
while(nroot(x)){
if(nroot(y=f[x]))
rot((c[f[y]][0]==y)^(c[y][0]==x)?x:y);
rot(x);
}
up(x);
}
void dp(R x){//dp预处理答案
R y,i,mp=x;
RG L mx=a[x];
for(i=he[x];i;i=ne[i]){
if(f[x]==(y=to[i]))continue;
f[y]=x;dp(y);
si[x]+=s[y];
if(mx<s[y])mx=s[y],mp=y;
}
if(mx<<1>(s[x]=si[x]+a[x])){
ans+=(s[x]-mx)<<1;
if(x!=mp)si[x]-=s[rc=mp];//子树过大
else tp[x]=1;//自己过大
}
else tp[x]=2,ans+=s[x]-1;//都不是很大
}
int main(){
R n,m,i,p=0,x,y;
RG L w,S;
in(n);in(m);
for(i=1;i<=n;++i)in(a[i]);
for(i=1;i<n;++i){
in(x);in(y);
to[++p]=y;ne[p]=he[x];he[x]=p;
to[++p]=x;ne[p]=he[y];he[y]=p;
}
dp(1);printf("%lld\n",ans);
while(m--){
in(x);in(w);
for(y=0;x;x=f[y=x]){
splay(x);
S=s[x]-s[lc];//算原来子树a总和,注意减s[lc]
ans-=tp[x]<2?(S-(tp[x]?a[x]:s[rc]))<<1:S-1;
S+=w;s[x]+=w;(y?si:a)[x]+=w;
if(s[y]<<1>S)si[x]+=s[rc],si[x]-=s[rc=y];//虚实切换
if(s[rc]<<1>S) tp[x]=0,ans+=(S-s[rc])<<1;//子树过大
else{
if(rc)si[x]+=s[rc],rc=0;//没有子树过大,一定变虚
if(a[x]<<1>S)tp[x]=1,ans+=(S-a[x])<<1;//自己过大
else tp[x]=2,ans+=S-1,rc=0;//都不是很大
}
}
printf("%lld\n",ans);
}
return 0;
}
洛谷P4338 [ZJOI2018]历史(LCT,树形DP,树链剖分)的更多相关文章
- P4338 [ZJOI2018]历史 LCT+树形DP
\(\color{#0066ff}{ 题目描述 }\) 这个世界有 n 个城市,这 n 个城市被恰好 \(n-1\) 条双向道路联通,即任意两个城市都可以 互相到达.同时城市 1 坐落在世界的中心,占 ...
- [HDU 5293]Tree chain problem(树形dp+树链剖分)
[HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...
- ⌈洛谷1505⌋⌈BZOJ2157⌋⌈国家集训队⌋旅游【树链剖分】
题目链接 [洛谷] [BZOJ] 题目描述 Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接.为了方便游客到达每个景点但又为了节约成本,T ...
- 洛谷P3128 [USACO15DEC]最大流Max Flow [树链剖分]
题目描述 Farmer John has installed a new system of pipes to transport milk between the stalls in his b ...
- 洛谷 P3258 [JLOI2014]松鼠的新家(树链剖分)
题目描述松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在”树“上. 松鼠想邀请小熊维尼前来 ...
- 洛谷 P3038 [USACO11DEC]牧草种植Grass Planting(树链剖分)
题解:仍然是无脑树剖,要注意一下边权,然而这种没有初始边权的题目其实和点权也没什么区别了 代码如下: #include<cstdio> #include<vector> #in ...
- 洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)
题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...
- 洛谷 P3258 [JLOI2014]松鼠的新家 树链剖分+差分前缀和优化
目录 题面 题目链接 题目描述 输入输出格式 输入格式 输出格式 输入输出样例 输入样例: 输出样例: 说明 说明 思路 AC代码 优化 优化后AC代码 总结 题面 题目链接 P3258 [JLOI2 ...
- 洛谷P2146 [NOI2015]软件包管理器 题解 树链剖分+线段树
题目链接:https://www.luogu.org/problem/P2146 本题涉及算法: 树链剖分: 线段树(区间更新及求和,涉及懒惰标记) 然后对于每次 install x ,需要将 x 到 ...
随机推荐
- Iframe和Frame中实现cookie跨域的方法(转载)
在Iframe和Frame中默认是不支持Cookie跨域的,但通过设置P3P协议相关的响应头可以解决这一问题.关于p3p协议: P3P: Platform for Privacy Preference ...
- [POI2007]旅游景点atr BZOJ1097
分析: 我们可以考虑,因为我们必须经过这些节点,那么我们可以将它状压,并且我们因为可以重复走,只是要求停顿前后,不要求遍历前后,那么我们之间存一下点与点之间的最短路,之后每次转移一下就可以了. f[i ...
- hung task机制
最近在修改内核源码的时候一直出现格式化磁盘的时候,进程会出现状态D,看内核日志会看到如下信息: INFO: task filebench: blocked seconds. Oct :: localh ...
- 大数据入门第二十二天——spark(二)RDD算子(1)
一.RDD概述 1.什么是RDD RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据抽象,它代表一个不可变.可分区.里面的元素可并行计算的 ...
- Exp3
利用不同免杀方式生成文件 1.msfvenom 使用msfvenom命令查看功能介绍 其中有: -p 选择一个载荷(或者叫模块) -l 载荷列表 -f 生成的文件格式 -e 编码方式 -l 编码次数 ...
- Linux内核中_IO,_IOR,_IOW,_IOWR宏的用法
#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) #define _IOR(type,nr,size) _IOC(_IOC_RE ...
- 校内模拟赛 Label
题意: n个点m条边的无向图,有些点有权值,有些没有.边权都为正.给剩下的点标上数字,使得$\sum\limits_{(u,v)\in E}len(u,v) \times (w[u] - w[v]) ...
- SSIS 连接数据
通常情况下,ETL方案需要同时访问两个或多个数据源,并把结果合并为单个数据流,输出到目标表中.为了向目标表中提供统一的数据结构,需要把多个数据源连接在一起.数据连接的另外一种用法,就是根据现有的数据, ...
- chrome浏览器插件 Octotree 让你浏览GitHub的时候像IDE 一样提供项目目录
GitHub 作为代码托管平台,竟然没有提供项目目录,方便用户在线快速浏览项目结构.所以,在线分析项目源码就会变得很繁琐,必须一层一层点击,然后再一次一次地向上返回.要知道,本来 GitHub 网站在 ...
- Beyond Compare文本对比中提示编辑禁止的解决方法
Beyond Compare是一款拥有文本比较功能的智能化软件,它支持在文本比较的同时,直接对差异文本进行修改.删除.编辑等一系列操作,这样一来,节约了文本对比的时间.但是在使用Beyond Comp ...