BZOJ 2333: [SCOI2011]棘手的操作 可并堆 左偏树 set
https://www.lydsy.com/JudgeOnline/problem.php?id=2333
需要两个结构分别维护每个连通块的最大值和所有连通块最大值中的最大值,可以用两个可并堆实现,也可以用一个可并堆一个平衡树实现,我看的题解用了内置红黑树的set,更加方便,所以我也用了set。
set的用法:https://blog.csdn.net/yas12345678/article/details/52601454 需要注意的是set的find和erase之类的操作返回输入的都是指针,在最后找最大值时,返回的是,也是指针实现的。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
const int maxn=;
multiset<int>s;
int n,q;
int fa[maxn]={},rt[maxn]={},ch[maxn][]={},cnt[maxn]={},add[maxn]={},val[maxn]={},zong=;
char op[]={};
inline void downdata(int x){
if(ch[x][]){val[ch[x][]]+=add[x];add[ch[x][]]+=add[x];}
if(ch[x][]){val[ch[x][]]+=add[x];add[ch[x][]]+=add[x];}
add[x]=;
}
void updata(int x){//这里的updata是把上面的所有标记传递下来
if(fa[x])updata(fa[x]);
downdata(x);
}
int merge(int x,int y){
if(!y)return x;
if(!x) return y;
downdata(x);downdata(y);
if(val[x]<val[y])swap(x,y);
ch[x][]=merge(ch[x][],y);fa[ch[x][]]=x;
if(ch[x][]<ch[x][])swap(ch[x][],ch[x][]);
cnt[x]=cnt[ch[x][]]+;
return x;
}
int Find(int x){
return fa[x]?Find(fa[x]):x;
}
inline int cle(int x){//把x与他的父亲儿子断绝关系,return堆顶
int t=merge(ch[x][],ch[x][]),y=fa[x];
fa[x]=ch[x][]=ch[x][]=;
if(x==ch[y][])ch[y][]=t;
if(x==ch[y][])ch[y][]=t;
fa[t]=y;
return Find(t);
}
inline void del(int x){
s.erase(s.find(x));
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){scanf("%d",&val[i]);s.insert(val[i]);}
scanf("%d",&q);int x,y,xx,yy;
for(int i=;i<=q;i++){
scanf("%s",op);
if(op[]=='A'){
scanf("%d",&x);
if(op[]==''){
scanf("%d",&y);
updata(x);del(val[Find(x)]);val[x]+=y;
s.insert(val[merge(x,cle(x))]);
}
else if(op[]==''){
scanf("%d",&y);
xx=Find(x);del(val[xx]);add[xx]+=y;val[xx]+=y;
s.insert(val[xx]);
}
else zong+=x;
}
else if(op[]=='F'){
if(op[]==''){
scanf("%d",&x);updata(x);printf("%d\n",val[x]+zong);
}
else if(op[]==''){
scanf("%d",&x);
printf("%d\n",val[Find(x)]+zong);
}
else{
printf("%d\n",*(--s.end())+zong);
}
}else{
scanf("%d%d",&x,&y);
yy=Find(y);xx=Find(x);
if(xx!=yy){
if(merge(xx,yy)==xx)del(val[yy]);
else del(val[xx]);
}
}
}
return ;
}
可并堆+set
这道题的另一个写法是离线+线段树,将所有需要并到一起的点离线处理编号在线段树上放到一起,也很清晰。
这里将点排序的方法大概是桶排序?
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
#define lc x*2
#define rc x*2+1
const int maxn=;
int n,q;
char ch[]={};
int val[maxn]={},rig[maxn]={},b[maxn]={},op[maxn][]={};
int e[maxn][]={},fa[maxn]={},cnt=,sum[maxn]={},tail=;
int a[maxn]={};
int xl[maxn*]={},xr[maxn*]={};
int mx[maxn*]={},ad[maxn*]={};
int id1,id2,v,zong=;
int getfa(int x){
return x==fa[x]?x:getfa(fa[x]);
}
inline void downdata(int x,int l,int r){
if(l!=r){
mx[lc]+=ad[x];mx[rc]+=ad[x];
ad[lc]+=ad[x];ad[rc]+=ad[x];
}
ad[x]=;
}
inline void updata(int x,int l,int r){
if(l!=r)mx[x]=max(mx[lc],mx[rc]);
}
void build(int x,int l,int r){
if(l==r){mx[x]=a[l];return;}
downdata(x,l,r);
int mid=(l+r)/;
build(lc,l,mid);
build(rc,mid+,r);
updata(x,l,r);
}
void addit(int x,int l,int r){
if(id1<=l&&r<=id2){ad[x]+=v;mx[x]+=v;return;}
int mid=(l+r)/;
downdata(x,l,r);
if(id1<=mid)addit(lc,l,mid);
if(id2>mid)addit(rc,mid+,r);
updata(x,l,r);
}
int getmx(int x,int l,int r){
if(id1<=l&&r<=id2){return mx[x];}
int mid=(l+r)/,mm=maxn*(-);
downdata(x,l,r);
if(id1<=mid)mm=max(getmx(lc,l,mid),mm);
if(id2>mid)mm=max(getmx(rc,mid+,r),mm);
updata(x,l,r);
return mm;
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++){scanf("%d",&val[i]);fa[i]=i;sum[i]=;}
scanf("%d",&q);
int x,y,xx,yy;
for(int i=;i<=q;i++){
scanf("%s",ch);
if(ch[]=='U'){
op[i][]=;
scanf("%d%d",&x,&y);op[i][]=x;op[i][]=y;
xx=getfa(x);yy=getfa(y);
if(xx==yy)continue;
if(xx>yy)swap(xx,yy);
fa[yy]=xx;e[++cnt][]=xx;e[cnt][]=yy;sum[xx]+=sum[yy];
}
else if(ch[]=='A'){
scanf("%d",&op[i][]);
if(ch[]==''){op[i][]=;scanf("%d",&op[i][]);}
else if(ch[]==''){op[i][]=;scanf("%d",&op[i][]);}
else op[i][]=;
}
else{
if(ch[]==''){op[i][]=;scanf("%d",&op[i][]);}
else if(ch[]==''){op[i][]=;scanf("%d",&op[i][]);}
else op[i][]=;
}
}
for(int i=;i<=n;i++){
if(fa[i]==i){
b[i]=tail+;tail+=sum[i];rig[i]=tail;
a[b[i]]=val[i];
}
}
for(int i=cnt;i>;i--){
b[e[i][]]=rig[e[i][]]-sum[e[i][]]+;
rig[e[i][]]=rig[e[i][]];rig[e[i][]]=b[e[i][]]-;
a[b[e[i][]]]=val[e[i][]];
}
for(int i=;i<=n;i++){fa[i]=i;xl[i]=xr[i]=i;/*cout<<i<<b[i]<<endl;*/}
build(,,n);
for(int i=;i<=q;i++){
if(op[i][]==){
xx=getfa(b[op[i][]]);yy=getfa(b[op[i][]]);
if(xx>yy)swap(xx,yy);
xr[xx]=xr[yy];fa[yy]=xx;
}
else if(op[i][]==){id1=b[op[i][]];id2=id1;v=op[i][];addit(,,n);}
else if(op[i][]==){
xx=getfa(b[op[i][]]);
id1=xl[xx];id2=xr[xx];v=op[i][];
addit(,,n);
}
else if(op[i][]==){
zong+=op[i][];
}
else if(op[i][]==){
id1=b[op[i][]];id2=id1;
printf("%d\n",getmx(,,n)+zong);
}
else if(op[i][]==){
xx=getfa(b[op[i][]]);id1=xl[xx];id2=xr[xx];
printf("%d\n",getmx(,,n)+zong);
}
else{
printf("%d\n",mx[]+zong);
}//id1=1;id2=2;
//cout<<getmx(1,1,n)<<' '<<1<<endl;
}
return ;
}
离线+线段树
BZOJ 2333: [SCOI2011]棘手的操作 可并堆 左偏树 set的更多相关文章
- bzoj 2333 [SCOI2011]棘手的操作 —— 可并堆
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2333 稍微复杂,参考了博客:http://hzwer.com/5780.html 用 set ...
- BZOJ 2333 [SCOI2011]棘手的操作 (可并堆)
码农题.. 很显然除了两个全局操作都能用可并堆完成 全局最大值用个multiset记录,每次合并时搞一搞就行了 注意使用multiset删除元素时 如果直接delete一个值,会把和这个值相同的所有元 ...
- BZOJ 2333: [SCOI2011]棘手的操作
题目描述 真的是个很棘手的操作.. 注意每删除一个点,就需要clear一次. #include<complex> #include<cstdio> using namespac ...
- BZOJ 2333 SCOI2011 棘手的操作 并查集+可并堆
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2333 ..题意概述就不写了,各位老爷如果是看着玩的可以去搜一下,如果是做题找来的也知道题干 ...
- 【BZOJ 2333 】[SCOI2011]棘手的操作(离线+线段树|可并堆-左偏树)
2333: [SCOI2011]棘手的操作 Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边 ...
- 2333: [SCOI2011]棘手的操作[写不出来]
2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1979 Solved: 772[Submit][Stat ...
- 2333: [SCOI2011]棘手的操作[离线线段树]
2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2325 Solved: 909[Submit][Stat ...
- 2333: [SCOI2011]棘手的操作[我不玩了]
2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1979 Solved: 772[Submit][Stat ...
- 【bzoj2333】 [SCOI2011]棘手的操作 可并堆+lazy标记
2016-05-31 21:45:41 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2333 (学习了黄学长的代码 有如下操作: U x y ...
随机推荐
- dockerfile创建镜像及容器
第一步: 从王总git上:http://git.oursdata.com/wangyue/dockerfiles.git 进入下图的文件夹中 然后执行以下的说明执行步骤 第二步: 开发环境dock ...
- 20155303 2016-2017-2 《Java程序设计》第一周学习总结
20155303 2016-2017-2 <Java程序设计>第一周学习总结 教材学习内容总结 浏览教材,根据自己的理解每章提出一个问题 Chapter1 Java平台概论:MyProgr ...
- 关于Java IO与NIO知识都在这里
由于内容比较多,我下面放的一部分是我更新在我的微信公众号上的链接,微信排版比较好看,更加利于阅读.每一篇文章下面我都把文章的主要内容给列出来了,便于大家学习与回顾. Java面试通关手册(Java学习 ...
- Linux多线程的使用一:互斥锁
多线程经常会在Linux的开发中用到,我想把平时的使用和思考记录下来,一是给自己做个备忘,二是分享给可能会用到的人. POSIX标准下互斥锁是pthread_mutex_t,与之相关的函数有: 1 i ...
- MySQL 5.6 GTID Replication【转】
一. MySQL 5.6引入了GTID的概念,那么GTID是何方神圣?其实也不复杂,就是一个全局事务标示符.使用GTID时,每次事务提交都会在binlog里生成1个唯一的标示符,它由UUID和事务ID ...
- ADB常用命令(二)
参考 http://adbshell.com/commands 常用命令 查看adb 版本 adb version 打印所有附加模拟器/设备的列表 adb devices 设备序列号 adb get ...
- linux用户权限 -> 系统特殊权限
set_uid 运行一个命令的时候,相当于这个命令的所有者,而不是执行者的身份. suid的授权方法 suid 权限字符s(S),用户位置上的x位上设置. 授权方法: passwd chmod u+s ...
- docker stack 部署 seafile(http)
=============================================== 2018/5/13_第1次修改 ccb_warlock == ...
- 利用vw+rem实现移动web适配布局
基本概念 1.单位 Px(CSS pixels) 像素 (px) 是一种绝对单位(absolute units), 因为无论其他相关的设置怎么变化,像素指定的值是不会变化的 其实是相对于某个设备而言的 ...
- mybatis之 # 与 $ 区别以及 sql 预编译
mybatis 中使用 sqlMap 进行 sql 查询时,经常需要动态传递参数,例如我们需要根据用户的姓名来筛选用户时,sql 如下: select * from user where name = ...