【bzoj2333 & luoguP3273】棘手的操作(线段树合并)
题目传送门:bzoj2333 luoguP3273
这操作还真“棘手”。。听说这题是可并堆题?然而我不会可并堆。于是我就写了线段数合并,然后调了一晚上,数据结构毁一生!!!QAQ……
其实这题也可以把合并强行看成树上的关系然后dfs序后直接线段树的,然而我菜啊。。看到连边就只能想到线段树合并。
首先用并查集维护图的连通性,然后对于每个连通块建一棵下标为点的编号的线段树,于是:
U=合并两棵树;
A1:单点加;
A2:区间加;
A3:因为是整体加,所以我们可以维护一个delta表示当前每个数被整体加了多少,然后输出时直接加上就好了;
F1:单点查询;
F2:区间查询;
然而还有一个F3整体查询最大值很难处理。于是我再开了一颗线段树,维护每个连通块内的最大值,修改时顺便在上面修改信息,F3操作可以直接在树上查询。
时间复杂度$ O(n \log n) $,然而常数极大。
两颗线段树+奇奇怪怪的维护方法,使写出来的代码膨胀到了3.6kB……然后,调试++,and then,(如果你写的不优美)MLE+TLE。经过了一番痛苦的调试后,终于过了。。。QAQ
又臭又长的代码:
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
#define maxn 300010
inline ll read()
{
ll x=; char c=getchar(),f=;
for(;c<''||''<c;c=getchar())if(c=='-')f=-;
for(;''<=c&&c<='';c=getchar())x=x*+c-'';
return x*f;
}
struct segment_tree1{
struct point{
int lc,rc,mx,delta;
}sgt[*maxn];
int tot;
void add(int now,int l,int r,int x,int y,int k)
{
if(x<=l&&r<=y)sgt[now].delta+=k,sgt[now].mx+=k;
else{
int mid=(l+r)>>;
if(x<=mid){
if(!sgt[now].lc)sgt[now].lc=++tot;
add(sgt[now].lc,l,mid,x,y,k);
}
if(mid<y){
if(!sgt[now].rc)sgt[now].rc=++tot;
add(sgt[now].rc,mid+,r,x,y,k);
}
sgt[now].mx=std::max(sgt[sgt[now].lc].mx,sgt[sgt[now].rc].mx);
if(sgt[now].mx!=-inf)sgt[now].mx+=sgt[now].delta;
}
}
int getmax(int now,int l,int r,int x,int y)
{
if(x<=l&&r<=y)return sgt[now].mx;
else{
int mid=(l+r)>>,mx=-inf;
if(x<=mid&&sgt[now].lc)mx=std::max(mx,getmax(sgt[now].lc,l,mid,x,y));
if(mid<y&&sgt[now].rc)mx=std::max(mx,getmax(sgt[now].rc,mid+,r,x,y));
return mx+sgt[now].delta;
}
}
void merge(int x,int y,int d)
{
d+=sgt[y].delta-sgt[x].delta;
if(!sgt[x].lc)sgt[x].lc=sgt[y].lc,sgt[sgt[x].lc].delta+=d,sgt[sgt[x].lc].mx+=d;
else if(sgt[y].lc)merge(sgt[x].lc,sgt[y].lc,d);
if(!sgt[x].rc)sgt[x].rc=sgt[y].rc,sgt[sgt[x].rc].delta+=d,sgt[sgt[x].rc].mx+=d;
else if(sgt[y].rc)merge(sgt[x].rc,sgt[y].rc,d);
sgt[x].mx=std::max(sgt[sgt[x].lc].mx,sgt[sgt[x].rc].mx)+sgt[x].delta;
}
}t1;
struct segment_tree2{
struct point{
int mx,delta;
}sgt[*maxn];
void add(int now,int l,int r,int x,int y,int k)
{
if(x<=l&&r<=y)sgt[now].delta+=k,sgt[now].mx+=k;
else{
int mid=(l+r)>>;
if(x<=mid)add(now<<,l,mid,x,y,k);
if(mid<y)add(now<<|,mid+,r,x,y,k);
sgt[now].mx=std::max(sgt[now<<].mx,sgt[now<<|].mx);
if(sgt[now].mx!=-inf)sgt[now].mx+=sgt[now].delta;
}
}
int getmax(int now,int l,int r,int x,int y)
{
if(x<=l&&r<=y)return sgt[now].mx;
else{
int mid=(l+r)>>,mx=-inf;
if(x<=mid)mx=std::max(mx,getmax(now<<,l,mid,x,y));
if(mid<y)mx=std::max(mx,getmax(now<<|,mid+,r,x,y));
return sgt[now].delta+mx;
}
}
}t2;
int rt[maxn],fa[maxn],a[maxn],delta;
int n,m;
char op[];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main()
{
n=read();
t1.tot=; delta=;
t1.sgt[].mx=t2.sgt[].mx=-inf;
for(int i=;i<=n;i++){
a[i]=read();
rt[i]=++t1.tot; fa[i]=i;
t1.add(rt[i],,n,i,i,a[i]);
t2.add(,,n,i,i,a[i]);
}
m=read();
for(int i=;i<=m;i++){
scanf("%s",op);
if(op[]=='U'){
int x=read(),y=read();
x=find(x); y=find(y);
if(x!=y){
fa[y]=x; t1.merge(rt[x],rt[y],);
t2.add(,,n,x,x,std::max(a[x],a[y])-a[x]); t2.add(,,n,y,y,-a[y]-inf);
a[x]=std::max(a[x],a[y]); a[y]=-inf;
}
}
else if(op[]=='A'){
if(op[]==''){
int x=read(),v=read(),fx=find(x);
t1.add(rt[fx],,n,x,x,v);
int t=t1.getmax(rt[fx],,n,,n);
t2.add(,,n,fx,fx,t-a[fx]);
a[fx]=t;
}
else if(op[]==''){
int x=read(),v=read(),fx=find(x);
t1.add(rt[fx],,n,,n,v);
t2.add(,,n,fx,fx,v);
a[fx]+=v;
}
else{
int v=read();
delta+=v;
}
}
else{
if(op[]==''){
int x=read(),fx=find(x);
printf("%d\n",t1.getmax(rt[fx],,n,x,x)+delta);
}
else if(op[]==''){
int x=read(),fx=find(x);
printf("%d\n",a[fx]+delta);
}
else printf("%d\n",t2.getmax(,,n,,n)+delta);
}
}
}
bzoj2333 & luoguP3273
可并堆的做法以后再补吧。。
【bzoj2333 & luoguP3273】棘手的操作(线段树合并)的更多相关文章
- 神奇的操作——线段树合并(例题: BZOJ2212)
什么是线段树合并? 首先你需要动态开点的线段树.(对每个节点维护左儿子.右儿子.存储的数据,然后要修改某儿子所在的区间中的数据的时候再创建该节点.) 考虑这样一个问题: 你现在有两棵权值线段树(大概是 ...
- 2019.01.17 bzoj2333: [SCOI2011]棘手的操作(启发式合并)
传送门 启发式合并菜题. 题意:支持与连通块有关的几种操作. 要求支持连边,单点修改,连通块修改,全局修改和单点查值,连通块查最大值和全局最大值. 我们对每个连通块和答案用可删堆维护最大值,然后用启发 ...
- 【BZOJ2333】棘手的操作(左偏树,STL)
[BZOJ2333]棘手的操作(左偏树,STL) 题面 BZOJ上看把... 题解 正如这题的题号 我只能\(2333\) 神TM棘手的题目... 前面的单点/联通块操作 很显然是一个左偏树+标记 ( ...
- [XJOI NOI2015模拟题13] C 白黑树 【线段树合并】
题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动 ...
- BZOJ2733 [HNOI2012]永无乡 【线段树合并】
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- bzoj 2243 [SDOI2011]染色(树链剖分+线段树合并)
[bzoj2243][SDOI2011]染色 2017年10月20日 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询 ...
- B20J_2733_[HNOI2012]永无乡_权值线段树合并
B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...
- 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree
原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...
- BZOJ5417[Noi2018]你的名字——后缀自动机+线段树合并
题目链接: [Noi2018]你的名字 题目大意:给出一个字符串$S$及$q$次询问,每次询问一个字符串$T$有多少本质不同的子串不是$S[l,r]$的子串($S[l,r]$表示$S$串的第$l$个字 ...
随机推荐
- FW:主流RPC框架
主流RPC框架 2015年10月27日 zman RPC 介绍目前在互联网公司比较流行的开源的RPC框架. RPC框架比较 语言 协议 服务治理 社区 机构 Hessian 多语言 he ...
- UEFI,BIOS,MBR,
UEFI启动是一种新的主板引导项,正被看做是有近20多年历史的BIOS 的继任者.顾名思义,快速启动是可以提高开机后操作系统的启动速度.由于开机过程中UEFI的介入 第一:安全性更强 UEFI启动需要 ...
- mysql 创建函数ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_f
mysql 创建函数的时候 报错 ERROR 1418 (HY000): This function has none of DETERMINISTIC, NO SQL, or READS SQL D ...
- Pytorch permute,contiguous
permute(dims),常用的维度转换方法 将tensor的维度换位 参数:dim(int)---换位顺序 >>>x = torch.randn(,,) >> ...
- 浅析Spring AOP
在正常的业务流程中,往往存在着一些业务逻辑,例如安全审计.日志管理,它们存在于每一个业务中,然而却和实际的业务逻辑没有太强的关联关系. 图1 这些逻辑我们称为横切逻辑.如果把横切的逻辑代码写在业务代码 ...
- Python中i = i + 1与i + = 1的区别
+=是对原本的实例做加1运算,l=l+[1]是对l+[1]之后重新把值赋给叫l的变量(和原来的l不同) 区别在于,一个修改数据结构本身(就地操作)b + = 1而另一个只是重新分配变量a = a + ...
- Linux系统——引导过程与服务控制
一.Linux开机启动原理(十步) (1)开机自检BIOS 开机检测,主板检测 (2)MBR引导 硬盘512字节 (3)GRUB菜单 操作系统菜单 (4)加载内核(kernel) 启动操作系统核心,根 ...
- es6的Set和Map数据结构
Set 和 Map 数据结构 Set WeakSet Map WeakMap Set § ⇧ 基本用法 ES6 提供了新的数据结构 Set.它类似于数组,但是成员的值都是唯一的,没有重复的值. Set ...
- [Python]关于return逻辑判断和短路逻辑
定义一个return...and..函数: def res(): ' 返回结果: >>> print(res()) 1234 定义一个return...or..函数: def res ...
- Java TreeMap详细介绍和使用示例
①对TreeMap有个整体认识 TreeMap是一个有序的key-value集合,它是通过红黑树实现的. TreeMap继承于AbstractMap,所以它是一个Map,即key-value集合. T ...