bzoj2333 [SCOI2011]棘手的操作(洛谷3273)
题目描述
有N个节点,标号从1到N,这N个节点一开始相互不连通。第i个节点的初始权值为a[i],接下来有如下一些操作:U x y: 加一条边,连接第x个节点和第y个节点A1 x v: 将第x个节点的权值增加vA2 x v: 将第x个节点所在的连通块的所有节点的权值都增加vA3 v: 将所有节点的权值都增加vF1 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
做法
我的想法是 离线+线段树区间修改, 预处理出每个操作联通块在DFS上的区间,然后上线段树就好了。
连边的时候,连的是这个点 并查集的祖先 ,而不是这个点,这样才能让所有相应联通块在连续的区间里(不理解就画一画)。
连边同时顺便维护每个联通块对应区间的L,R。
正经吐槽
细节很多。
由于是有负数的,一定在建立线段树时把值都赋成-INF,还有查询越界的return -INF
LazyTag……
预处理时并查集是找祖先连边用的,预处理完要把并查集清空(复原)。
别的细节我写在代码注释里面好了
代码
#include<bits/stdc++.h>
#define MAXN 300005
#define INF 0x7f7f7f7f
using namespace std;
int read(){
int x=,t=;char c=getchar();
while(c<''||c>''){if(c=='-')t=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*t;
}
int N,Q,a[MAXN],father[MAXN],cnt1,lazy[MAXN<<],X[MAXN],Y[MAXN],cnt2,cont,pos[MAXN],dfso[MAXN],vis[MAXN],L[MAXN],R[MAXN],last[MAXN];
char s[];
int find(int x){return father[x]==x?x:father[x]=find(father[x]);}
struct Node{int l,r,Max;}tree[MAXN<<];
struct Edge{int other,pre;}e[MAXN];
struct Operation{int type,x,y;}q[MAXN];
void connect(int x,int y){
if(x==y)return;
e[++cnt2]=(Edge){y,last[x]};
last[x]=cnt2;
}
void DFS(int x){
cont++;L[x]=R[x]=pos[x]=cont,dfso[cont]=x; //dfso是dfs序数组,pos数组是点对应的dfs序位置
for(int i=last[x];i;i=e[i].pre)DFS(e[i].other);
}
void Pushdown(int k){
if(!lazy[k])return;
tree[k<<].Max+=lazy[k],lazy[k<<]+=lazy[k];
tree[k<<|].Max+=lazy[k],lazy[k<<|]+=lazy[k];
lazy[k]=;
}
void Build_tree(int k,int l,int r){
tree[k].Max=-INF; //初值赋成-INF
tree[k].l=l,tree[k].r=r; int mid=l+r>>;
if(l==r){tree[k].Max=a[dfso[l]];return;}
Build_tree(k<<,l,mid); Build_tree(k<<|,mid+,r);
tree[k].Max=max(tree[k<<].Max,tree[k<<|].Max);
}
void Modify(int k,int l,int r,int x){
if(tree[k].l>r||tree[k].r<l)return;
if(l<=tree[k].l&&tree[k].r<=r){tree[k].Max+=x,lazy[k]+=x;return ;}
Pushdown(k);
Modify(k<<,l,r,x); Modify(k<<|,l,r,x);
tree[k].Max=max(tree[k<<].Max,tree[k<<|].Max);
}
int Query(int k,int l,int r){
if(tree[k].l>r||tree[k].r<l)return -INF; //越界返回-INF
if(l<=tree[k].l&&tree[k].r<=r)return tree[k].Max;
Pushdown(k);
return max( Query(k<<,l,r),Query(k<<|,l,r) );
}
int main()
{
N=read();
for(int i=;i<=N;i++)a[i]=read(),father[i]=i;
Q=read();
for(int i=;i<=Q;i++){
scanf("%s",s);
if(s[]=='U'){
q[i].type=;
int x,y;
q[i].x=x=read(),q[i].y=y=read();
int fx=find(x), fy=find(y);
cnt1++; father[fy]=fx;
X[cnt1]=fx, Y[cnt1]=fy; //存一下要连的边,是连的祖先!
}
if(s[]=='A'){
if(s[]=='')q[i].type=,q[i].x=read(),q[i].y=read(); //x点+v
if(s[]=='')q[i].type=,q[i].x=read(),q[i].y=read(); //x点联通块+v
if(s[]=='')q[i].type=,q[i].x=read(); //全体+v
}
if(s[]=='F'){
if(s[]=='')q[i].type=,q[i].x=read(); //询问x点
if(s[]=='')q[i].type=,q[i].x=read(); //询问x点所在块
if(s[]=='')q[i].type=; //全体询问
}
}
for(int i=cnt1;i>;i--)connect(X[i],Y[i]);
for(int i=;i<=N;i++)if(!vis[find(i)]){
DFS(find(i));vis[find(i)]=; //跑DFS序
}
for(int i=;i<=N;i++)father[i]=i; //复原并查集
Build_tree(,,N);
for(int i=;i<=Q;i++){
if(q[i].type==){
int fx=find(q[i].x),fy=find(q[i].y);
L[fx]=min(L[fx],L[fy]), R[fx]=max(R[fx],R[fy]); //合并时维护联通块对应区间的L,R
father[fy]=fx;
}
//简单的线段树操作
if(q[i].type==)Modify(,pos[q[i].x],pos[q[i].x],q[i].y);
if(q[i].type==){int fx=find(q[i].x);Modify(,L[fx],R[fx],q[i].y);}
if(q[i].type==)Modify(,,N,q[i].x);
if(q[i].type==)printf("%d\n",Query(,pos[q[i].x],pos[q[i].x]));
if(q[i].type==){int fx=find(q[i].x);printf("%d\n",Query(,L[fx],R[fx]));}
if(q[i].type==)printf("%d\n",Query(,,N));
}
return ;
}
//haha
不正经吐槽
我是周六上午上课时写写画画 思考着这个题如何离线,下午和dalao们说了这个题 他们就去写在线的线段树合并了。
一遍写的比较顺利。
接着我就开始调错。
我没赋初值-INF 怎么改都是0
主函数里没有调用 Build_tree 怎么改都是-INF
lazytag没有判断 怎么改都WrongAnswer
最后一次 发现错在了 ↓
void Pushdown(int k){
if(!lazy[k])return;
tree[k<<].Max+=k,lazy[k<<]+=k;
tree[k<<|].Max+=k,lazy[k<<|]+=k;
lazy[k]=;
}
把k当成了lazy[k] ,还看不出来 , 结果一Pushdown出现了一些本来就没有的数。弱智。
我开始质疑我的智商水平了
推送
http://music.163.com/#/song/524164335/?userid=476005944
寻梦环游记 - Remember Me-泠鸢
歌手:泠鸢yousa
bzoj2333 [SCOI2011]棘手的操作(洛谷3273)的更多相关文章
- bzoj2333[SCOI2011]棘手的操作 洛谷P3273 [SCOI2011]棘手的操作
2333? 先记一下吧,这题现在全部都是照着题解做的,因为怎么改都改不出来,只好对着题解改,以后还要再做过 以后再也不用指针了!太恶心了!空指针可不止直接特判那么简单啊,竟然还要因为空指针写奇怪的分类 ...
- 真--可并堆模板--BZOJ2333: [SCOI2011]棘手的操作
n<=300000个点,开始是独立的,m<=300000个操作: 方法一:单点修改.查询,区间修改.查询?等等等等这里修改是块修改不是连续的啊,那就让他连续呗!具体方法:离线后,每次连接两 ...
- BZOJ2333 [SCOI2011]棘手的操作 堆 左偏树 可并堆
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2333 题意概括 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i ...
- [bzoj2333] [SCOI2011]棘手的操作 (可并堆)
//以后为了凑字数还是把题面搬上来吧2333 发布时间果然各种应景... Time Limit: 10 Sec Memory Limit: 128 MB Description 有N个节点,标号从1 ...
- bzoj千题计划217:bzoj2333: [SCOI2011]棘手的操作
http://www.lydsy.com/JudgeOnline/problem.php?id=2333 读入所有数据,先模拟一遍所有的合并操作 我们不关心联通块长什么样,只关心联通块内有谁 所以可以 ...
- 2019.01.17 bzoj2333: [SCOI2011]棘手的操作(启发式合并)
传送门 启发式合并菜题. 题意:支持与连通块有关的几种操作. 要求支持连边,单点修改,连通块修改,全局修改和单点查值,连通块查最大值和全局最大值. 我们对每个连通块和答案用可删堆维护最大值,然后用启发 ...
- BZOJ2333:[SCOI2011]棘手的操作(Splay)
Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 x v: ...
- BZOJ2333 [SCOI2011]棘手的操作 【离线 + 线段树】
题目 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 x v: 将第x个节点的权 ...
- bzoj2333 [SCOI2011]棘手的操作
用set维护每个联通块里的最值,multiset维护所有块里的最值,并查集维护连通性,然后随便搞搞就行了,合并时候采用启发式合并.复杂度O(nlognlogn),大概勉强过的程度,反正跑的很慢就是了. ...
随机推荐
- 使用 Sublime 或其他编辑器调试 Tampermonkey 油猴脚本
作者说由于 Chrome 安全限制,没办法调用外部编辑器调试,但提供了一个间接办法,那就是脚本中使用@require file:///引入本地文件的形式,具体的方法是 打开 chrome://exte ...
- 路飞学城Python-Day48
49-清除浮动1:给父盒子设置高度 给父盒子设置高度,这种方式不灵活,公司的产品修改的时候,要求父盒子高度变大, 不可能去手动修改 尽量不要给父元素去修改高度,不建议这样的方式 <!DOCTYP ...
- 路飞学城Python-Day25
- hp soap扩展最全说明,附天气预报调用的例子
自从php5开始,我们可以不用通过php nusoap来创建php soap web service 和调用 soap了,php5内置了 soap扩展.只需要在php.ini中开启soap的exten ...
- github删除项目or仓库
1. 登录 github (要注册账号) 2. 登录后点击右上侧头像,选择 Your profile . 3. 选择Repositories,可以查看已有的库,选择要删除的库进入. 4. 选择Sett ...
- (七)u-boot2013.01.01 for s5pv210:《u-boot启动流程》
转载请注明地址:http://blog.csdn.net/zsy2020314/article/details/9824035 1.关于启动流程 1.1 启动阶段分为3个,bl0,bl1,bl2.下面 ...
- [LeetCode] 860. 柠檬水找零 lemonade-change(贪心算法)
思路: 收到5块时,只是添加:收到十块时,添加10块,删除一个5块:收到20块时,添加20,删除一个10块一个5块,或者直接删除3个5块(注意:这里先删除5+10优于3个5) class Soluti ...
- crm 系统项目(三) 自动分页
crm 系统项目(三) 自动分页 需求: 1. 做一个自动分页, 每15条数据1页 2. 让当前页数在中间显示 3. 上一页, 下一页 注意情况: 1.总页数 小于 规定显示的页数 2. 左右两边极值 ...
- openvswith Frequently Asked Questions
Open vSwitch <http://openvswitch.org> 参考地址:http://git.openvswitch.org/cgi-bin/gitweb.cgi?p=ope ...
- dockerfile centos+jdk+时区设置
1.参考博客:https://blog.csdn.net/yjk13703623757/article/details/68944549 2.dockerfile如下 # Base os image ...