【bzoj2333】 [SCOI2011]棘手的操作 可并堆+lazy标记
2016-05-31 21:49
483 查看
2016-05-31 21:45:41
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2333
(学习了黄学长的代码
有如下操作:
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: 输出所有节点中,权值最大的节点的权值
~~~~~~~~~~~~~~萌萌哒分割线~~~~~~~~~~~~~~~~~~~~~~~~
U就是一个合并操作,用可并堆,注意tag的下传
A1将x点从所在堆中删去,修改权值后再加进去。删除就是合并两棵子树,在将merge后节点的父亲改为x的父亲,返回find(merge后的节点),因为x有可能是根
A2的话在所在堆的堆顶上加tag
A3再开一个变量记录好了
F1 记得将祖先的tag标记pushdown
F2 堆顶+A3
F3 比较复杂,网上很多做法都是在来一棵左偏树,维护各个堆的堆顶。在这里学习了黄学长,用multiset来维护,注意要实时更新里面的信息。
View Code
Submit: 1621 Solved: 620
[Submit][Status][Discuss]
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个整数,a[1], a[2], …, a
,代表N个节点的初始权值。
再下一行输入一个整数Q,代表接下来的操作数。
最后输入Q行,每行的格式如题目描述所示。
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
对于80%的数据,保证 N<=100000,Q<=100000
对于100%的数据,保证 N<=300000,Q<=300000
对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a
<=1000
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2333
(学习了黄学长的代码
有如下操作:
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: 输出所有节点中,权值最大的节点的权值
~~~~~~~~~~~~~~萌萌哒分割线~~~~~~~~~~~~~~~~~~~~~~~~
U就是一个合并操作,用可并堆,注意tag的下传
A1将x点从所在堆中删去,修改权值后再加进去。删除就是合并两棵子树,在将merge后节点的父亲改为x的父亲,返回find(merge后的节点),因为x有可能是根
A2的话在所在堆的堆顶上加tag
A3再开一个变量记录好了
F1 记得将祖先的tag标记pushdown
F2 堆顶+A3
F3 比较复杂,网上很多做法都是在来一棵左偏树,维护各个堆的堆顶。在这里学习了黄学长,用multiset来维护,注意要实时更新里面的信息。
#include<bits/stdc++.h> #define inf 1000000000 #define ll long long #define N 300005 using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,Q,overadd,fa ,tag ,ls ,rs ,v ,dep ; multiset<int> st; char ch[5]; int find(int x){ while(fa[x])x=fa[x]; return x; } void pushdown(int x){ if(!tag[x])return; if(ls[x])tag[ls[x]]+=tag[x],v[ls[x]]+=tag[x]; if(rs[x])tag[rs[x]]+=tag[x],v[rs[x]]+=tag[x]; tag[x]=0; } int merge(int x,int y){ if(!x||!y)return x+y; if(v[x]<v[y])swap(x,y); pushdown(x); rs[x]=merge(rs[x],y); fa[rs[x]]=x; if(dep[ls[x]]<dep[rs[x]])swap(ls[x],rs[x]); dep[x]=dep[rs[x]]+1; return x; } void unite(int x,int y){ int fx=find(x),fy=find(y); if(fx!=fy){ int t=merge(fx,fy); if(t==fx)st.erase(st.find(v[fy])); else st.erase(st.find(v[fx])); } } void Pushdown(int x){ if(fa[x])Pushdown(fa[x]); pushdown(x); } int del(int x){ int t=merge(ls[x],rs[x]),f=fa[x]; ls[x]=rs[x]=fa[x]=0; if(x==ls[f])ls[f]=t; else rs[f]=t; fa[t]=f; return find(t); } void add(int x,int val){ Pushdown(x); st.erase(st.find(v[find(x)])); v[x]+=val; st.insert(v[merge(x,del(x))]); } void change(int x,int val){ int f=find(x); tag[f]+=val;v[f]+=val; st.erase(st.find(v[f]-val));st.insert(v[f]); } void getval(int x){ Pushdown(x); printf("%d\n",v[x]+overadd); } int main(){ n=read(); for(int i=1;i<=n;i++)v[i]=read(),st.insert(v[i]); Q=read(); while(Q--){ scanf("%s",ch); if(ch[0]=='A'){ if(ch[1]=='1'){ int x=read(),y=read();add(x,y); } else if(ch[1]=='2'){ int x=read(),y=read();change(x,y); } else overadd+=read(); } else if(ch[0]=='F'){ if(ch[1]=='1')getval(read()); else if(ch[1]=='2')getval(find(read())); else printf("%d\n",*--st.find(inf)+overadd); } else{ int x=read(),y=read();unite(x,y); } } return 0; }
View Code
2333: [SCOI2011]棘手的操作
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1621 Solved: 620
[Submit][Status][Discuss]
Description
有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: 输出所有节点中,权值最大的节点的权值
Input
输入的第一行是一个整数N,代表节点个数。接下来一行输入N个整数,a[1], a[2], …, a
,代表N个节点的初始权值。
再下一行输入一个整数Q,代表接下来的操作数。
最后输入Q行,每行的格式如题目描述所示。
Output
对于操作F1, F2, F3,输出对应的结果,每个结果占一行。Sample Input
30 0 0
8
A1 3 -20
A1 2 20
U 1 3
A2 1 10
F1 3
F2 3
A3 -10
F3
Sample Output
-1010
10
HINT
对于30%的数据,保证 N<=100,Q<=10000对于80%的数据,保证 N<=100000,Q<=100000
对于100%的数据,保证 N<=300000,Q<=300000
对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a
<=1000
相关文章推荐
- ios开发UI篇—Kvc简单介绍
- C++类之const
- 数据库的简单查询和连接查询
- Exception和继承自Exception的RuntimeException区别
- Django笔记 解决找不到vcvarsall.bat的错误
- 使用cJSON创建JSON字符串
- 字符串处理
- poj 1172 Street Race
- noip 2010 关押罪犯 (二分图染色 并茶几)
- 微信也能鉴别山寨iPhone【微信高级教程2】
- iOS开发之旅--ReactiveCocoa使用小结
- CPU利用率与Load Average的区别
- C语言学习篇-4运算符及其优先级
- java 面试
- Ubuntu14.04上VNC安装与使用
- 第14、15周学习进度表
- 《剑指offer》——从尾到头打印链表
- HDU 1394 Minimum Inversion Number
- 指向学生类的指针
- Android__数据存储