【LCT】历史(P4338)

2024-01-29 23:18
文章标签 历史 lct p4338

本文主要是介绍【LCT】历史(P4338),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

正题

P4338


题目大意

有一棵树,告诉你每个点access的次数(带修改),问实链切换的最多次数


解题思路

先考虑离线的做法:

对于点 x,其不同儿子的子树access会使实链切换(对于点 x access 同理),每次都让不同儿子的子树 access,显然可以让答案最大化

但答案不一定是 s z x − 1 sz_x-1 szx1(最后无法切换),因为如果存在一个儿子 y 满足 s z y > s z x − s z y sz_y > sz_x-sz_y szy>szxszy,即该子树大小大于其他子树大小之和,那么不存在操作使得 y 中的每次access都被切换掉

所以当 s z y × 2 ≥ s z x + 1 sz_y\times 2\geq sz_x+1 szy×2szx+1 时答案为 ( s z x − s z y ) × 2 (sz_x-sz_y)\times 2 (szxszy)×2(最多切换这么多次不同的), 否则为 s z x − 1 sz_x-1 szx1


然后再考虑在线的做法:

考虑用LCT维护,实边连接满足 s z y × 2 ≥ s z x + 1 sz_y\times 2\geq sz_x+1 szy×2szx+1 的儿子(不存在则不连)

每次修改可能会修改当前点到根节点的实链,那么只需考虑对该段的影响

对于原来是实边的,显然加了之后仍然满足,不影响,对于原来是虚边的,先减去原来的贡献,然后再考虑连边计算贡献

每经过一次虚边,那么其他儿子的 sz 就必定大于 当前点的 sz,那么sz至少会变大一倍,所以最多经过 log 条虚边

时间复杂度 O ( n l o g n ) O(n\ log\ n) O(n log n)


code

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
#define N 400400
ll n,m,x,y,tot,ans,top,a[N],h[N],d[N];
struct rec
{ll to,nx;
}e[N<<1];
void add(ll x,ll y)
{e[++tot].to=y;e[tot].nx=h[x];h[x]=tot;return;
}
struct LCT
{#define ls son[x][0]#define rs son[x][1]ll v[N],ss[N],s[N],fa[N],son[N][2];bool NR(ll x){return fa[x]&&(son[fa[x]][0]==x||son[fa[x]][1]==x);}bool IRS(ll x){return son[fa[x]][1]==x;}void push_up(ll x){s[x]=s[ls]+s[rs]+ss[x]+v[x];return;}void rotate(ll x){ll y=fa[x],z=fa[y],k=IRS(x),g=son[x][!k];if(NR(y))son[z][IRS(y)]=x;if(g)fa[g]=y;fa[x]=z;fa[y]=x;son[x][!k]=y;son[y][k]=g;push_up(y);return;}void Splay(ll x){while(NR(x)){if(NR(fa[x])){if(IRS(x)==IRS(fa[x]))rotate(fa[x]);else rotate(x);}rotate(x);}push_up(x);return;}ll get(ll x){if(rs)return (v[x]+ss[x])*2;else if(v[x]*2>=(s[x]-s[ls])+1)return ss[x]*2;else return (s[x]-s[ls])-1;}void access(ll x,ll z){Splay(x);ans-=get(x);//减去原有贡献v[x]+=z;s[x]+=z;if(rs&&s[rs]*2<s[x]-s[ls]+1){//断去原来的边ss[x]+=s[rs];rs=0;}ans+=get(x);ll y=x;x=fa[x];for(;x;x=fa[y=x]){Splay(x);ans-=get(x);ss[x]+=z;s[x]+=z;if(rs&&s[rs]*2<s[x]-s[ls]+1){ss[x]+=s[rs];rs=0;}if(s[y]*2>=s[x]-s[ls]+1){//连接新的实边rs=y;ss[x]-=s[rs];}ans+=get(x);}return;}
}T;
void dfs(ll x)//初始连边
{ll hs=0;T.v[x]=a[x];for(ll i=h[x];i;i=e[i].nx){ll y=e[i].to;if(y==T.fa[x])continue;T.fa[y]=x;dfs(y);T.ss[x]+=T.s[y];if(T.s[y]>T.s[hs])hs=y;}T.s[x]=T.v[x]+T.ss[x];if(T.s[hs]*2>=T.s[x]+1){T.son[x][1]=hs;T.ss[x]-=T.s[hs];ans+=(T.v[x]+T.ss[x])*2;}else if(T.v[x]*2>=T.s[x]+1){ans+=T.ss[x]*2;}else ans+=T.s[x]-1;return;
}
int main()
{scanf("%lld%lld",&n,&m);for(ll i=1;i<=n;++i)scanf("%lld",&a[i]);for(ll i=1;i<n;++i){scanf("%lld%lld",&x,&y);add(x,y);add(y,x);}dfs(1);printf("%lld\n",ans);while(m--){scanf("%lld%lld",&x,&y);T.access(x,y);printf("%lld\n",ans);}return 0;
}

这篇关于【LCT】历史(P4338)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/658479

相关文章

查看提交历史 —— Git 学习笔记 11

查看提交历史 查看提交历史 不带任何选项的git log-p选项--stat 选项--pretty=oneline选项--pretty=format选项git log常用选项列表参考资料 在提交了若干更新,又或者克隆了某个项目之后,你也许想回顾下提交历史。 完成这个任务最简单而又有效的 工具是 git log 命令。 接下来的例子会用一个用于演示的 simplegit

从希腊神话到好莱坞大片,人工智能的七大历史时期值得铭记

本文选自historyextra,机器之心编译出品,参与成员:Angulia、小樱、柒柒、孟婷 你可能听过「技术奇点」,即本世纪某个阶段将出现超级智能,那时,技术将会以人类难以想象的速度飞速发展。同样,黑洞也是一个奇点,在其上任何物理定律都不适用;因此,技术奇点也是超越未来理解范围的一点。 然而,在我们到达那个奇点之前(假设我们能到达),还存在另一个极大的不连续问题,我将它称之

Git Gui 查看分支历史的时候中文显示乱码

如图所示 在Git Gui工具栏上选择-编辑-选项: 选择:Default File Contents Encoding, change为UTF-8 成功:

2024年9月7日历史上的今天大事件早读

251年9月7日 三国时期军事家司马懿逝世 1298年9月7日 马可-波罗与鲁思梯谦合著《马可-波罗行记》 1625年9月7日 魏忠贤下令禁毁东林书院 1689年9月7日 中俄《尼布楚条约》签订 1812年9月7日 俄法博罗季诺决战,标志着拿破仑的军队覆灭开始 1822年9月7日 巴西独立 1853年9月7日 上海小刀会起义 1901年9月7日 《辛丑条约》签订 1904

OceanBase 4.x 存储引擎解析:如何让历史库场景成本降低50%+

据国际数据公司(IDC)的报告显示,预计到2025年,全球范围内每天将产生高达180ZB的庞大数据量,这一趋势预示着企业将面临着更加严峻的海量数据处理挑战。随着数据日渐庞大,一些存储系统会出现诸如存储空间扩展难、性能下降甚至卡顿的情况,影响业务系统的正常运转,增加企业的数据处理成本。众多企业已经开始积极寻求如何在保证处理效率的同时,进一步降低数据处理成本。特别是在历史库(冷数据)场景中,这种需求显

REMEMBERING HISTORY WITH CONVOLUTIONAL LSTM FOR ANOMALY DETECTION——利用卷积LSTM记忆历史进行异常检测

上海科技大学的文章,上海科技大学有个组一直在做这方面的工作,好文章挺多的还有数据集。 ABSTRACT 本文解决了视频中的异常检测问题,由于异常是无界的,所以异常检测是一项极具挑战性的任务。我们通过利用卷积神经网络(CNN或ConvNet)对每一帧进行外观编码,并利用卷积长期记忆(ConvLSTM)来记忆与运动信息相对应的所有过去的帧来完成这项任务。然后将ConvNet和ConvLSTM与

在 Git 中 Checkout 历史版本

昨天写代码的时候,误删了一个文件。今天发现的时候,commit 已经 push 到版本库了。本想用 git reset 回退版本,找回文件后重新提交。但是想起 Git 是一个版本控制系统哎,直接从版本库里 checkout 出某个文件的历史版本不就好了? 想法挺好,但是很久没用这个功能,自己已经不记得具体的命令了。于是查了下手册,把和 checkout 历史版本有关的几个命令都记录一下。

【HDU】5333 Undirected Graph【LCT+BIT】

传送门:【HDU】5333 Undirected Graph my  code: my~~code: #pragma comment(linker, "/STACK:1024000000")#include <stdio.h>#include <string.h>#include <map>#include <algorithm>using namespace std ;typed

用异步序列优雅的监听 SwiftData 2.0 中历史追踪记录(History Trace)的变化

概述 WWDC 24 一声炮响为我们送来 Swift 6.0 的同时,也颇为“低调”的推出了 SwiftData 2.0。在新版本的 SwiftData 中,苹果为其新增了多个激动人心的新特性,其中就包括历史记录追踪(History Trace)。 不过,历史记录追踪目前看起来似乎有些“白璧微瑕”,略微让人有些不爽。在这里就让我们看看如何利用 Swift 结构化并发中的异步序列(Asy

P4842 城市旅行(拆贡献 + LCT)

https://www.luogu.com.cn/problem/P4842 发现题目就是要维护一个LCT,然后我们只要把pushup写成功了就行。 那我们现在就不管LCT了,就单纯想用一棵二叉查找树怎么维护。分母是好搞的,分子我们要想点办法。 考虑右子树对左子树的贡献,我们假设处理出一个 L [ k ] L[k] L[k] 表示左子树中每个值乘以左边界的可选数量,我们现在再乘上右子树的大