【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: linux screen -recorder by ffcast convert
fcast -s ffmpeg -r 20 -vcodec huffyuv out.avi 上面的命令会让你选择一个要录制的区域,然后呢,就会你就可以操作了,操作完后退回去按 q 键退出结束.如果你想 ...
- 前端开发 - CSS - 下
CSS: 12.display 13.浮动效果 14.浮动特性 15.浮动产生的问题和解决方法 16.float京东导航栏 17.position 18.z-index 19.京东案例 12.disp ...
- 并发编程 - 线程 - 1.开启线程的两种方式/2.进程与线程的区别/3.Thread对象的其他属性或方法/4.守护线程
1.开启线程的两种方式: 进程,线程: 进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合)而线程才是cpu上的执行单位) 1.同一个进程内的多个线程共享该进程内的地址资源 2.创建线 ...
- embedded-redis在单元测试中的使用
1 背景 参考链接:https://github.com/kstyrc/embedded-redis 2 使用 2.1 引入依赖 <dependency> <groupId>c ...
- Flask之中间件
from flask import Flask, flash, redirect, render_template, request app = Flask(__name__) app.secret_ ...
- (0.2.5)Mysql安装——RPM方式安装
rpm安装mysql 卸载与安装服务端 一.安装服务端与客户端 #查看RPM包中所有的文件shell> rpm -qpl mysql-community-server-version-dis ...
- 006-Shell printf 命令
一.概述 printf 命令模仿 C 程序库(library)里的 printf() 程序. printf 由 POSIX 标准所定义,因此使用 printf 的脚本比使用 echo 移植性好. pr ...
- 011-HQL中级1-Hive快捷查询:不启用Mapreduce job启用Fetch task三种方式介绍
如果你想查询某个表的某一列,Hive默认是会启用MapReduce Job来完成这个任务,如下: hive; Total MapReduce jobs Launching Job out since ...
- 脱离JVM? Hadoop生态圈的挣扎与演化
本文由知乎<大数据应用与实践>专栏 李呈祥授权发布,版权所有归作者,转载请联系作者! 新世纪以来,互联网及个人终端的普及,传统行业的信息化及物联网的发展等产业变化产生了大量的数据,远远超出 ...
- JVM堆内存相关的启动参数:年轻代、老年代和永久代的内存分配
如果想观察JVM进程占用的堆内存,可以通过命令工具jmap或者可视化工具jvisualvm.exe.JVM这些启动参数都拥有默认值,如果想了解JVM的内存分配策略,最好手动设置这些启动参数.再通过JD ...