题目

有N个节点,标号从1到N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:

U x y: 加一条边,连接第x个节点和第y个节点

A1 x v: 将第x个节点的权值增加v

A2 x v: 将第x个节点所在的连通块的所有节点的权值都增加v

A3 v: 将所有节点的权值都增加v

F1 x: 输出第x个节点当前的权值

F2 x: 输出第x个节点所在的连通块中,权值最大的节点的权值

F3: 输出所有节点中,权值最大的节点的权值

输入格式

输入的第一行是一个整数N,代表节点个数。

接下来一行输入N个整数,a[1], a[2], …, a[N],代表N个节点的初始权值。

再下一行输入一个整数Q,代表接下来的操作数。

最后输入Q行,每行的格式如题目描述所示。

输出格式

对于操作F1, F2, F3,输出对应的结果,每个结果占一行。

输入样例

3

0 0 0

8

A1 3 -20

A1 2 20

U 1 3

A2 1 10

F1 3

F2 3

A3 -10

F3

输出样例

-10

10

10

提示

对于30%的数据,保证 N<=100,Q<=10000

对于80%的数据,保证 N<=100000,Q<=100000

对于100%的数据,保证 N<=300000,Q<=300000

对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000

题解

据说此题很多人堆套堆,怎么这么难写

我那么弱当然是用线段树啦

我觉得线段树的确好写到不知哪里去

对于所有操作,似乎在线段树上都很好实现,唯一的难点就在于点的编号

那么问题就转化成了,给定一种编号方法,使任意时刻同一个联通块内的所有点编号连续

只需要分两种情况想就很容易实现了:

我们想象,一开始所有点相互独立,没什么关系

①当两个独立的点相连时,它们的编号一定是连续的,否则此时就不满足所需性质

那我们就先用链表将它们连起来,表示编号连续

②当两个联通块相连时,由我们维护的性质得:两个联通块内部的点编号一定是连续的,现在我们需要两个联通块编号连续,我们只需要将它们的编号衔接起来就好了,那么我们把其中一个联通块所对应的链 接到另一个联通块对应的链末尾就好了

可以发现,这样子操作之后,我们就会得出若干个链,表示链上的点编号必须按链上的顺序

所以我们按链的顺序标号,就能保证所有时刻联通块内部点的编号连续

取链头链尾用并查集实现

我们在询问的时候,也要用上并查集,并且链接顺序与标号的时候相同,保证每个联通块目前的代表元一定是标号时编号最小的点,所以我们再维护并查集的大小就可以轻松求出每次操作的区间啦~

数据结构部分就只用实现一个简单的线段树

比堆套堆不知道要好写到哪里去

丑丑的代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
#define ls (u << 1)
#define rs (u << 1 | 1)
using namespace std;
const int maxn = 300005,maxm = 100005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
struct Query{int opt,a,b,c;}q[maxn];
int n,m,pre[maxn],post[maxn],id[maxn],Hash[maxn],val[maxn],cnt;
int nxt[maxn],siz[maxn];
int mx[4 * maxn],tag[4 * maxn];
char opt[10];
int findu(int u){return u == pre[u] ? u : pre[u] = findu(pre[u]);}
int findd(int u){return u == post[u] ? u : post[u] = findd(post[u]);}
void build(int u,int l,int r){
if (l == r) {mx[u] = val[Hash[l]]; return;}
int mid = l + r >> 1;
build(ls,l,mid);
build(rs,mid + 1,r);
mx[u] = max(mx[ls],mx[rs]);
}
void pd(int u){
if (tag[u]){
mx[ls] += tag[u]; tag[ls] += tag[u];
mx[rs] += tag[u]; tag[rs] += tag[u];
tag[u] = 0;
}
}
void modify(int u,int l,int r,int L,int R,int v){
if (l >= L && r <= R){mx[u] += v; tag[u] += v; return;}
pd(u);
int mid = l + r >> 1;
if (mid >= L) modify(ls,l,mid,L,R,v);
if (mid < R) modify(rs,mid + 1,r,L,R,v);
mx[u] = max(mx[ls],mx[rs]);
}
int query(int u,int l,int r,int L,int R){
if (l >= L && r <= R) return mx[u];
pd(u);
int mid = l + r >> 1;
if (mid >= R) return query(ls,l,mid,L,R);
else if (mid < L) return query(rs,mid + 1,r,L,R);
else return max(query(ls,l,mid,L,R),query(rs,mid + 1,r,L,R));
}
int main(){
n = read();
for (int i = 1; i <= n; i++) val[i] = read(),pre[i] = post[i] = i;
m = read();
int fa,fb,sa,sb;
for (int i = 1; i <= m; i++){
scanf("%s",opt);
if (opt[0] == 'U'){
q[i].opt = 0,q[i].a = read(),q[i].b = read();
fa = findu(q[i].a); fb = findu(q[i].b);
if (fa == fb) continue;
sa = findd(q[i].a); sb = findd(q[i].b);
nxt[sa] = fb;
pre[fb] = fa;
post[sa] = sb;
}
else if (opt[0] == 'A'){
q[i].a = read();
if (opt[1] == '1') q[i].opt = 1,q[i].b = read();
else if (opt[1] == '2') q[i].opt = 2,q[i].b = read();
else q[i].opt = 3;
}else {
if (opt[1] == '1') q[i].opt = 4,q[i].a = read();
else if (opt[1] == '2') q[i].opt = 5,q[i].a = read();
else q[i].opt = 6;
}
}
for (int i = 1; i <= n; i++){
if (id[i]) continue;
int u = findu(i);
while (u) id[u] = ++cnt,Hash[cnt] = u,u = nxt[u];
}
build(1,1,n);
for (int i = 1; i <= n; i++) pre[i] = i,siz[i] = 1;
for (int i = 1; i <= m; i++){
switch(q[i].opt){
case 0:
fa = findu(q[i].a); fb = findu(q[i].b);
if (fa != fb){
siz[fa] += siz[fb];
pre[fb] = fa;
}
break;
case 1:
modify(1,1,n,id[q[i].a],id[q[i].a],q[i].b);
break;
case 2:
fa = findu(q[i].a);
modify(1,1,n,id[fa],id[fa] + siz[fa] - 1,q[i].b);
break;
case 3:
modify(1,1,n,1,n,q[i].a);
break;
case 4:
printf("%d\n",query(1,1,n,id[q[i].a],id[q[i].a]));
break;
case 5:
fa = findu(q[i].a);
printf("%d\n",query(1,1,n,id[fa],id[fa] + siz[fa] - 1));
break;
case 6:
printf("%d\n",mx[1]);
break;
}
}
return 0;
}

BZOJ2333 [SCOI2011]棘手的操作 【离线 + 线段树】的更多相关文章

  1. 2333: [SCOI2011]棘手的操作[离线线段树]

    2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2325  Solved: 909[Submit][Stat ...

  2. BZOJ 2333 棘手的操作(离线+线段树+带权并查集)

    这题搞了我一天啊...拍不出错原来是因为极限数据就RE了啊,竟然返回WA啊.我的线段树要开8倍才能过啊... 首先可以发现除了那个加边操作,其他的操作有点像线段树啊.如果我们把每次询问的联通块都放在一 ...

  3. bzoj2333 [SCOI2011]棘手的操作(洛谷3273)

    题目描述 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作:U x y: 加一条边,连接第x个节点和第y个节点A1 x v: 将第x个节点的权 ...

  4. 【bzoj2333 & luoguP3273】棘手的操作(线段树合并)

    题目传送门:bzoj2333 luoguP3273 这操作还真“棘手”..听说这题是可并堆题?然而我不会可并堆.于是我就写了线段数合并,然后调了一晚上,数据结构毁一生!!!QAQ…… 其实这题也可以把 ...

  5. 真--可并堆模板--BZOJ2333: [SCOI2011]棘手的操作

    n<=300000个点,开始是独立的,m<=300000个操作: 方法一:单点修改.查询,区间修改.查询?等等等等这里修改是块修改不是连续的啊,那就让他连续呗!具体方法:离线后,每次连接两 ...

  6. P3273-[SCOI2011]棘手的操作【线段树,并查集】

    正题 题目链接:https://www.luogu.com.cn/problem/P3273 题目大意 \(n\)个点有权值,要求支持操作 连接两个点 单点加权 联通块加权 全图加权 单点询问 联通块 ...

  7. bzoj千题计划217:bzoj2333: [SCOI2011]棘手的操作

    http://www.lydsy.com/JudgeOnline/problem.php?id=2333 读入所有数据,先模拟一遍所有的合并操作 我们不关心联通块长什么样,只关心联通块内有谁 所以可以 ...

  8. 洛谷.3273.[SCOI2011]棘手的操作(左偏树)

    题目链接 还是80分,不是很懂. /* 七个操作(用左偏树)(t2表示第二棵子树): 1.合并:直接合并(需要将一个t2中原有的根节点删掉) 2.单点加:把这个点从它的堆里删了,加了再插入回去(有负数 ...

  9. 洛谷P3273 [SCOI2011] 棘手的操作 [左偏树]

    题目传送门 棘手的操作 题目描述 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 ...

随机推荐

  1. Python-OpenCV——Image Blurring(Image Smoothing)

    通过将图像与低通滤波器内核卷积来实现图像模糊.它有助于消除噪音.它实际上从图像中去除了高频内容(例如:噪声,边缘).因此在此操作中边缘会有点模(嗯,有模糊技术,也不会模糊边缘). OpenCV主要提供 ...

  2. Memcached笔记之分布式算法

    1.根据余数进行分散:离散度高,但是增加或者移除服务器的时候,缓存充足的代价非常大.添加服务器后,余数就会产生巨变,这样就无法获取与保存时相同的服务器,从而音像缓存的命中率. 2.Consistent ...

  3. Ball Coloring

    6552: Ball Coloring 时间限制: 1 Sec  内存限制: 128 MB提交: 13  解决: 7[提交][状态][讨论版][命题人:admin] 题目描述 There are N ...

  4. 2018.2.27 JavaScript数组方法应用

    JavaScript数组方法应用 1.找出元素item在给定数组arr中的位置 function indexOf(arr,item){ return arr.indexOf(item); } func ...

  5. AddDbContext was called with configuration, but the context type 'NewsContext' only declares a parameterless constructor?

    问题 An error occurred while starting the application. ArgumentException: AddDbContext was called with ...

  6. dSYM文件

    来到新公司后,前段时间就一直在忙,前不久 项目 终于成功发布上线了,最近就在给项目做优化,并排除一些线上软件的 bug,因为项目中使用了友盟统计,所以在友盟给出的错误信息统计中能比较方便的找出客户端异 ...

  7. jQuery plugin : bgStretcher 背景图片切换效果插件

    转自:http://blog.dvxj.com/pandola/jQuery_bgStretcher.html bgStretcher 2011 (Background Stretcher)是一个jQ ...

  8. 第3-5课 填充左侧菜单/品牌的添加 Thinkphp5商城第四季

    目录 左侧菜单的填充 品牌的添加 form标签里要加上method="post" enctype="multipart/form-data" form标签里如果 ...

  9. STM32CUBEMX入门学习笔记3:HAL库以及STM32CUBE相关资料

    微雪课堂:http://www.waveshare.net/study/article-629-1.html 之前的正点原子的例程资料 硬石科技stm32cube: 链接:https://pan.ba ...

  10. Oracle redo与undo 第一弹

      一. 什么是redo(用于前滚数据) redo也就是重做日志文件(redo log file),Oracle维护着两类重做日志文件:在线(online)重做日志文件和归档(archived)重做日 ...