传送门(洛谷)

人生第一道九条可怜……神仙操作……

看着题解理解了一个早上才勉强看懂怎么回事……

简化一下题目就是:已知每一个点access的总次数,求一个顺序使虚实边转化的次数最多

考虑一下,对于x的一个子树,如果他已经有了一个最优序列,那么一定不会和他祖先的最优序列产生冲突。为什么呢?因为对他的所有祖先来说,只要是来自他的子树的access都会对他到根的路径产生贡献,所以对他的祖先来说,无论access的是子树的哪一个节点都是等价的,于是我们可以在祖先的最优序列中将所有x的子树的access调换位置,并不会影响最优解

于是单独考虑每一个点x,只有x的子树以及x本身的access会对x的实子边产生影响(x的access会是x没有实子边),如果切换的两点不在x的同一子树(或都是x),每切换一次答案+1,。于是我们可以转化为这么一个问题,有$sum[x]$个球(表示x及他的子树总共有多少次access操作),每种颜色的球有$sum[c]$个(表示x的每一个子树以及x本身的操作次数),求一种排列,使他们两两相邻颜色不同的对数最大。很明显,如果没有一种球的出现次数大于球的总数的一半,那么答案就是$sum[x]-1$,否则的话,出现次数大于一半的球必定有某几对不会对答案产生贡献,答案就是$2*(sum[x]-max(sum[c]))$

当$sum[c]*2>sum[x]+1$时取后者

 

直接树形dp就行了

然后考虑一下怎么修改呢?

首先,对某一个点的修改,只会对该点到根的路径上的答案有影响

因为是加一个值,如果有一个点的子树$sum$大于父节点$sum$的一半,那么代入上式可以发现答案是不变的

那么我们是不是可以用树剖的思路?对于子树$sum$大于自己$sum$一半的点连实边,其余的连虚边,然后access的时候更改虚实边即可

为了方便计算以前的贡献,可以保存一下以前贡献的类型(某子树过大、自己过大、都不是很大)算的时候就省去了一些判断的时间。

 //minamoto
#include<cstdio>
#include<iostream>
#define ll long long
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,:;}
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char obuf[<<],*o=obuf;
void print(ll x){
if(x>) print(x/);
*o++=x%+;
}
const int N=,M=N*;
int ver[M],Next[M],head[N],tot;
int fa[N],ch[N][];short tp[N];
ll sum[N],si[N],a[N],ans;
inline bool isroot(int x){return ch[fa[x]][]!=x&&ch[fa[x]][]!=x;}
#define lc ch[x][0]
#define rc ch[x][1]
inline void pushup(int x){sum[x]=sum[lc]+sum[rc]+si[x]+a[x];}
inline void rotate(int x){
int y=fa[x],z=fa[y],d=ch[y][]==x;
if(!isroot(y)) ch[z][ch[z][]==y]=x;
fa[x]=z,fa[y]=x,fa[ch[x][d^]]=y,ch[y][d]=ch[x][d^],ch[x][d^]=y,pushup(y);
}
inline void splay(int x){
for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){
if(!isroot(y))
((ch[y][]==x)^(ch[z][]==y))?rotate(x):rotate(y);
rotate(x);
}
pushup(x);
}
void dp(int x){
int mp=x;ll mx=a[x];
for(int i=head[x];i;i=Next[i]){
int v=ver[i];
if(v==fa[x]) continue;
fa[v]=x,dp(v);
si[x]+=sum[v];
if(mx<sum[v]) mp=v,mx=sum[v];
}
if((mx<<)>(sum[x]=si[x]+a[x])){
ans+=(sum[x]-mx)<<;
x==mp?tp[x]=:si[x]-=sum[rc=mp];
}
else tp[x]=,ans+=sum[x]-;
}
int main(){
//freopen("testdata.in","r",stdin);
int n=read(),m=read();
for(int i=;i<=n;++i) a[i]=read();
for(int i=;i<n;++i){
int u=read(),v=read();
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
}
dp();print(ans),*o++='\n';
while(m--){
int x=read(),w=read();
for(int y=;x;x=fa[y=x]){
splay(x);
ll s=sum[x]-sum[lc];
ans-=tp[x]<?(s-(tp[x]?a[x]:sum[rc]))<<:s-;
s+=w,sum[x]+=w,(y?si:a)[x]+=w;
if(sum[y]<<>s) si[x]+=sum[rc],si[x]-=sum[rc=y];
if(sum[rc]<<>s) tp[x]=,ans+=(s-sum[rc])<<;
else{
if(rc) si[x]+=sum[rc],rc=;
(a[x]<<>s)?(tp[x]=,ans+=(s-a[x])<<):(tp[x]=,ans+=s-,rc=);
}
}
print(ans),*o++='\n';
}
fwrite(obuf,o-obuf,,stdout);
return ;
}

[BZOJ5212][ZJOI2018]历史的更多相关文章

  1. BZOJ5212 ZJOI2018历史(LCT)

    首先相当于最大化access的轻重边交换次数. 考虑每个点作为战场(而不是每个点所代表的国家与其他国家交战)对答案的贡献,显然每次产生贡献都是该点的子树内(包括自身)此次access的点与上次acce ...

  2. 【BZOJ5212】[ZJOI2018]历史(Link-Cut Tree)

    [BZOJ5212][ZJOI2018]历史(Link-Cut Tree) 题面 洛谷 BZOJ 题解 显然实际上就是给定了一棵树和每个点被\(access\)的次数,求解轻重链切换的最大次数. 先考 ...

  3. [ZJOI2018]历史

    [ZJOI2018]历史 最大化access轻重链的切换次数 考虑一个点的贡献,即它交换重儿子的次数 发现这个次数只和它自己ai以及每个儿子的子树次数和有关. 一个关键的事实是: 我们可以自上而下进行 ...

  4. 【BZOJ5212】[ZJOI2018] 历史(LCT大黑题)

    点此看题面 大致题意: 给定一棵树每个节点\(Access\)的次数,求最大虚实链切换次数,带修改. 什么是\(Access\)? 推荐你先去学一学\(LCT\)吧. 初始化(不带修改的做法) 首先考 ...

  5. bzoj 5212: [Zjoi2018]历史

    Description 九条可怜是一个热爱阅读的女孩子. 这段时间,她看了一本非常有趣的小说,这本小说的架空世界引起了她的兴趣. 这个世界有n个城市,这n个城市被恰好n?1条双向道路联通,即任意两个城 ...

  6. Luogu4338 ZJOI2018 历史 LCT、贪心

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

  7. P4338 [ZJOI2018]历史 LCT+树形DP

    \(\color{#0066ff}{ 题目描述 }\) 这个世界有 n 个城市,这 n 个城市被恰好 \(n-1\) 条双向道路联通,即任意两个城市都可以 互相到达.同时城市 1 坐落在世界的中心,占 ...

  8. [ZJOI2018]历史(LCT)

    这篇还发了洛谷题解 [Luogu4338] [BZOJ5212] 题解 题意 给出一棵树,给定每一个点的 \(access\) 次数,计算轻重链切换次数的最大值,带修改. 先考虑不带修改怎么做 假设 ...

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

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

随机推荐

  1. FastDFS 分布式文件系统

    1       学习目标 了解项目中使用FastDFS的原因和意义. 掌握FastDFS的架构组成部分,能说出tracker和storage的作用. 了解FastDFS+nginx上传和下载的执行流程 ...

  2. Android 重写EditText回车事件

    之前遇到的问题没来得及记录下来,趁今晚有空就重新回忆并写下了. 我们在用到EditText这个空间时经常需要重写软键盘中的回车事件以配合我们接下来的响应,比如点击回车变成搜索.发送.完成等. Edit ...

  3. 一张图记住TCP/IP通讯中的IP地址配置

    TCP/IP通讯情景: 用网线将计算机A(服务器Server)和计算机B(Client)连接起来.程序代码在计算机A中,计算机B中安装有TCP/IP通讯助手. (图中屏幕大的是计算机A,屏幕小的笔记本 ...

  4. 取得MapReduce的Thread Dump

    ====2016/5/20: 经过上级指示,为了MR性能调优,需要截取MR的服务器的线程堆栈(Thread Dump) 战友介绍的方法是这样的: ①.使用ps命令[ps -ef | grep java ...

  5. Cannot change version of project facet Dynamic Web Module to 2.4.

    解决办法,找到项目目录,将.settings  target  .classpath  .project 删除 重新引入项目 原因是 web.xml 文件里<web-app 里的与.settin ...

  6. 保证Service不被Kill的解决方案

    1.Service设置成START_STICKY(onStartCommand方法中),kill 后会被重启(等待5秒左右),重传Intent,保持与重启前一样 2.通过 startForegroun ...

  7. Google Tango Java实例程序

    Java API:https://developers.google.com/tango/apis/java/reference/ 1. java_augmented_reality_example ...

  8. 深入理解linux的权限设置和SUID,SGID以及粘滞位

    我们知道文件的权限可以用三个八进制数字表示.其实文件的权限应该用四个八进制来表示,不过用 ls -l 命令时,只显示三个罢了.那个没有显示的八进制数字其实是第一个,它用来设定一些特殊权限.这个八进制数 ...

  9. vs下C# WinForm 解决方案里面生成的文件都是什么作用?干什么的?

    Properties文件夹 定义你程序集的属性 项目属性文件夹 一般只有一个 AssemblyInfo.cs 类文件,用于保存程序集的信息,如名称,版本等,这些信息一般与项目属性面板中的数据对应,不需 ...

  10. 学习tomcat(一)----用IDEA调试tomcat源码

    一直在使用tomcat,但却不怎么熟悉tomcat的"运作流程",今天就 参照参考文章进行了代码搭建(代码的github在文末),并修改了一些操作.学习下tomcat的" ...