【BZOJ5212】[ZJOI2018]历史(Link-Cut Tree)
【BZOJ5212】[ZJOI2018]历史(Link-Cut Tree)
题面
题解
显然实际上就是给定了一棵树和每个点被\(access\)的次数,求解轻重链切换的最大次数。
先考虑不带修改的答案。
如果直接考虑全局的答案会很麻烦。
考虑每一个在每一个点处被切换的次数。
显然这个子树之和其子树内的点的\(access\)次数相关,和子树外的点无关。
而在这个点处被切换只有它的子树中不在同一棵子树内的两个点先后进行\(access\)。
对于一个点统计其不同子树内的\(access\)次数和,那么对于当前点而言,等价于有子树个数种颜色,每种颜色可以使用若干次,求一个放置方案数,使得相邻颜色不同的组数最多。
这个东西貌似是场\(agc\)的\(a\)题????
假设颜色总和是\(s\),最大值为\(p\),那么答案就是\(min\{s-1,2*(s-p)\}\)
原因大概就是看看出现次数最多的那个多不多,如果不是很多的话就可以穿插的放。(强行解释.jpg)
那么这样子可以进行一次\(dfs\),\(O(n)\)的算出答案。
然后现在存在了修改操作。
首先发现这个东西是一个加法操作,然后发现会影响的只有到达根的这一段路径。
那么考虑一下\(s-1<2*(s-p)\)推出来是\(2p<s+1\)。
而这样一次操作之后,路径上的\(s\)会做加法,而\(p\)呢????
来一点骚操作,我们对于\(2s_v\le s_u+1\)的、存在父子关系的两个点\(u,v\)之间连上一条轻边,在\(2s_v>s_u+1\)的\(u,v\)之间连上一条重边。
然后我们似乎就完成了一次重链剖分,可以证明每个点只会拥有不超过一个重儿子。
那么也可以发现到根节点的轻边数量是\(log\)级别的。
继续看看,发现进行区间加法的时候,重儿子显然还是满足上述条件,直接跳过不需要考虑。
那么对于一个轻儿子特殊的考虑一下是否需要修改其状态。
那么动态的修改轻重儿子就是\(LCT\)可以完成的事情啦。
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAX 400400
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int n,m,hson[MAX];
ll a[MAX],s[MAX],ss[MAX],ans;
struct Node{int ch[2],ff;}t[MAX];
bool isroot(int x){return t[t[x].ff].ch[0]!=x&&t[t[x].ff].ch[1]!=x;}
void pushup(int x){s[x]=s[t[x].ch[0]]+s[t[x].ch[1]]+ss[x]+a[x];}
void rotate(int x)
{
int y=t[x].ff,z=t[y].ff;
int k=t[y].ch[1]==x;
if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
t[x].ch[k^1]=y;t[y].ff=x;
pushup(y);pushup(x);
}
void Splay(int x)
{
while(!isroot(x))
{
int y=t[x].ff,z=t[y].ff;
if(!isroot(y))
(t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
rotate(x);
}
}
void dfs(int u,int ff)
{
ll mx=a[u];int ms=u;s[u]=a[u];t[u].ff=ff;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)
{
dfs(e[i].v,u),s[u]+=s[e[i].v];
if(s[e[i].v]>mx)mx=s[e[i].v],ms=e[i].v;
}
ss[u]=s[u]-a[u];
if(2*mx>s[u])
{
ans+=(s[u]-mx)*2;
if(ms==u)hson[u]=0;
else hson[u]=1,t[u].ch[1]=ms,ss[u]-=mx;
}
else ans+=s[u]-1,hson[u]=2;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
dfs(1,0);printf("%lld\n",ans);
while(m--)
{
int x=read(),w=read();
for(int y=0;x;y=x,x=t[x].ff)
{
Splay(x);
ll S=s[x]-s[t[x].ch[0]];
if(hson[x]==0)ans-=(S-a[x])*2;
if(hson[x]==1)ans-=(S-s[t[x].ch[1]])*2;
if(hson[x]==2)ans-=S-1;
S+=w;s[x]+=w;if(y)ss[x]+=w;else a[x]+=w;
if(s[y]*2>S)ss[x]+=s[t[x].ch[1]],ss[x]-=s[y],t[x].ch[1]=y;
if(s[t[x].ch[1]]*2>S)hson[x]=1,ans+=(S-s[t[x].ch[1]])*2;
else
{
if(t[x].ch[1])ss[x]+=s[t[x].ch[1]],t[x].ch[1]=0;
if(a[x]*2>S)hson[x]=0,ans+=(S-a[x])*2;
else hson[x]=2,ans+=S-1,t[x].ch[1]=0;
}
}
printf("%lld\n",ans);
}
return 0;
}
【BZOJ5212】[ZJOI2018]历史(Link-Cut Tree)的更多相关文章
- link cut tree 入门
鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...
- Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题
A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...
- Link/cut Tree
Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...
- 洛谷P3690 Link Cut Tree (模板)
Link Cut Tree 刚开始写了个指针版..调了一天然后放弃了.. 最后还是学了黄学长的板子!! #include <bits/stdc++.h> #define INF 0x3f3 ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门
link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...
- P3690 【模板】Link Cut Tree (动态树)
P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...
- Link Cut Tree学习笔记
从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...
- [CodeForces - 614A] A - Link/Cut Tree
A - Link/Cut Tree Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, ...
随机推荐
- Django ORM 反向查询
一/一对多反向查询 先定义两个模型,一个是A,一个是B,是一对多的类型. class A(models.Model): name= models.CharField('名称', max_lengt ...
- Go Web --- 创建一个Article的增删改查
掌握数据的增删改查之后,就可以做一些小demo,巩固一下基础,让语法更加熟练,所以下面是按照Go web编程里面的文章管理操作,写的一个代码: package main import ( " ...
- 哈尔滨工程大学ACM预热赛
https://ac.nowcoder.com/acm/contest/554#question A #include <bits/stdc++.h> using namespace st ...
- Es5中的类和静态方法 继承
Es5中的类和静态方法 继承(原型链继承.对象冒充继承.原型链+对象冒充组合继承) // es5里面的类 //1.最简单的类 // function Person(){ // this.name='张 ...
- Eclipse lombok java
Stablehttps://projectlombok.org/features/all Lombok介绍及使用方法 - holten - 博客园http://www.cnblogs.com/holt ...
- vs快捷键 C#
快速构建构造函数 输入 ctor 然后按 TAB 键 快速构建自动属性 在变量那里,右击鼠标,点“重构”--“封装字段” Visual Studio快捷键 [VS2008/VS2005] ****** ...
- C#设计模式之9:模板方法
模板方法 模板方法是一个方法,定义了算法的步骤,并允许子类为一个或多个步骤提供实现. 本例中用冲泡咖啡和茶的例子来说明: 上图说明了冲泡咖啡和茶的步骤,可以看出冲泡咖啡和茶的步骤差不多,很相似,先来看 ...
- servlet ServletContext
一.Servlet简介 1.什么是Servlet Servlet 运行在服务端的Java小程序,是sun公司提供一套规范(接口),用来处理客户端请求.响应给浏览器的动态资源.但servlet的实质就是 ...
- java.lang.NoClassDefFoundError: org/apache/log4j/Priority的问题解决
在pom 文件中添加 <dependency> <groupId>log4j</groupId> <artifactId>log4j</artif ...
- webpack安裝和卸載
webpack安裝和卸載 安裝: 先裝好node和npm: 安裝package.json:進入到根目錄,運行npm init 新建全局webpack:cd退到全局目錄,運行npm install -g ...