传送门(洛谷)

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

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

简化一下题目就是:已知每一个点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. Linux实战教学笔记14:用户管理初级(上)

    第十四节 用户管理初级(上) 标签(空格分隔): Linux实战教学笔记-陈思齐 ---更多资料点我查看 1,账号管理 1.1 管理用户命令汇总 命令 注释说明(特殊颜色的必须掌握) useradd增 ...

  2. Unmarshaller解析xml文件

    参考地址:http://linbulu.iteye.com/blog/2295919 Girl.xml文件 <?xml version="1.0" encoding=&quo ...

  3. 【LA3523 训练指南】圆桌骑士 【双连通分量】

    题意 有n个骑士经常举行圆桌会议,商讨大事.每次圆桌会议至少应有3个骑士参加,且相互憎恨的骑士不能坐在圆桌旁的相邻位置.如果发生意见分歧,则需要举手表决,因此参加会议的骑士数目必须是奇数,以防赞同和反 ...

  4. Codeforces 721E DP

    大概思路及题意看这篇博客吧 我的理解:设f[i]表示处理到第i个区间,能唱的最多的歌,g[i]是保证f[i]最大时最靠左的点.那么f[i] = max(f[j] + (r[i] - max(l[i], ...

  5. Hibernate入门级实例

    一.开发环境 Win8 + jdk1.7 + MyEclipse + Tomcat5.0 + MySQL 说明:其实Hibernate是非常独立的框架,根本不需要MyEclipse,Eclipse,T ...

  6. [Training Video - 7] [Database connection] Various databases which are supported, Drivers for database connection, SQL Groovy API

    Various databases which are supported Drivers for database connection groovy.sql.Sql package SoapUI怎 ...

  7. JDK1.6 1.7 1.8 多版本windows安装 执行命令java -version 版本不变的问题

    现在Windows的java安装已经没有解压版本,Oracle官方也不会再提供了,只有安装程序 所以每当安装一次JDK,都会将 java.exe.javaw.exe.javaws.exe三个可执行文件 ...

  8. data cleaning

    Cleaning data in Python   Table of Contents Set up environments Data analysis packages in Python Cle ...

  9. Yii2在Form中处理短信验证码的Validator,耦合度最低的短信验证码验证方式

    短信验证码在目前大多数web应用中都会有,本文介绍一个基于Yii2 Validator方式的验证码验证方式. 在其他文章中看到的方式大多比较难做到一次封装,多次重用. 使用此方式的好处自然不用多说,V ...

  10. UVa 11996 Jewel Magic (splay + Hash + 二分)

    题意:给定一个长度为n的01串,你的任务是依次执行如表所示的m条指令: 1 p c 在第p个字符后插入字符,p = 0表示在整个字符串之前插入2 p 删除第p个字符,后面的字符往前移3 p1 p2反转 ...