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

题面

洛谷

BZOJ

题解

显然实际上就是给定了一棵树和每个点被\(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)的更多相关文章

  1. link cut tree 入门

    鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...

  2. Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题

    A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...

  3. Link/cut Tree

    Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...

  4. 洛谷P3690 Link Cut Tree (模板)

    Link Cut Tree 刚开始写了个指针版..调了一天然后放弃了.. 最后还是学了黄学长的板子!! #include <bits/stdc++.h> #define INF 0x3f3 ...

  5. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  6. bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门

    link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...

  7. P3690 【模板】Link Cut Tree (动态树)

    P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...

  8. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

  9. [CodeForces - 614A] A - Link/Cut Tree

    A - Link/Cut Tree Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, ...

随机推荐

  1. 线程锁(互斥锁Mutex)及递归锁

    一.线程锁(互斥锁) 在一个程序内,主进程可以启动很多个线程,这些线程都可以访问主进程的内存空间,在Python中虽然有了GIL,同一时间只有一个线程在运行,可是这些线程的调度都归系统,操作系统有自身 ...

  2. 【学习总结】vi/vim命令是使用

    每次要么想不起来用,要么进去了出不来,真是醉了.痛定思痛此处填坑. 参考教程:菜鸟教程vi/vim 实验环境:借Git-bash宝地一用 注意:记住关键的步骤! 按i a o进入输入模式(即使有时按v ...

  3. 消除element.style { }

    1.在写前台页面时,我们会发现控制台里会自动出现一些样式覆盖掉我们定义的样式: 解决的办法: 把被覆盖的样式单独定义出来,并在样式后面加上 !important,表示高优先级.

  4. react双组件传值和传参

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Java遍历HashMap并修改(remove)(转载)

    遍历HashMap的方法有多种,比如通过获取map的keySet, entrySet, iterator之后,都可以实现遍历,然而如果在遍历过程中对map进行读取之外的操作则需要注意使用的遍历方式和操 ...

  6. css特殊样式

    span{ color: blue; border:1px solid black;}.extra span{ color: inherit;} 清除原有样式 text-decoration: non ...

  7. CLOUD设置过滤方案不共享

    1.打开BOS,找到应用框架-动态表单-过滤方案另存 2.找到共享给他人,把可见性全部去掉

  8. SQL Server2012数据库开启远程连接

    在我们使用SQL Server数据库的时候很重要的一点就是开启数据库的远程连接,这是因为很多时候数据库部署在远程的服务器上会比较方便,而部署在客户端的话,由于客户端不固定,所以需要经常去部署,这样容易 ...

  9. Fetch API & Delete & HTTP Methods

    Fetch API & Delete & HTTP Methods vue https://developer.mozilla.org/en-US/docs/Web/API/Fetch ...

  10. python 网络编程 IO多路复用之epoll

    python网络编程——IO多路复用之epoll 1.内核EPOLL模型讲解     此部分参考http://blog.csdn.net/mango_song/article/details/4264 ...