bzoj 2333 [SCOI2011]棘手的操作 —— 可并堆
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2333
稍微复杂,参考了博客:http://hzwer.com/5780.html
用 set 维护全局的最大值就可以方便地删除和查询了;
大概就是写一堆关于可并堆的子函数吧;
这里还用了斜堆,但其实并不明白原因是什么...
斜堆和左偏树只有一点点不同,它不用 dis ,而是每次都交换左右儿子,随机地保证了复杂度?
要注意 solvetag 函数是要把跟 x 有关的所有 lzy 关系都处理掉,所以也要处理 x 到其儿子的;
还有 del 处的顺序,小心不要让 set 查询的东西为空。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
int const maxn=3e5+;
int n,m,a[maxn],ls[maxn],rs[maxn],fa[maxn],lzy[maxn],ad,sta[maxn],top;
multiset<int>st;
char ch[];
int find(int x){while(fa[x])x=fa[x]; return x;}
void pushdown(int x)
{
if(!lzy[x])return;
if(ls[x])lzy[ls[x]]+=lzy[x],a[ls[x]]+=lzy[x];
if(rs[x])lzy[rs[x]]+=lzy[x],a[rs[x]]+=lzy[x];
lzy[x]=;
}
int merge(int x,int y)
{
if(!x||!y)return x+y;
if(a[x]<a[y])swap(x,y);
pushdown(x);
rs[x]=merge(rs[x],y);
fa[rs[x]]=x;
swap(ls[x],rs[x]);
return x;
}
void solvetag(int x)
{
// x=fa[x]; //从 x 开始,使 x 对儿子没有 lzy 的关联
while(x)sta[++top]=x,x=fa[x];
while(top)pushdown(sta[top]),top--;
}
int del(int x)
{
solvetag(x);
int f=fa[x],k=merge(ls[x],rs[x]);
ls[x]=rs[x]=fa[x]=;
fa[k]=f;
if(ls[f]==x)ls[f]=k;
else rs[f]=k;
return find(k);
}
int rd()
{
int ret=,f=; char cc=getchar();
while(cc<''||cc>''){if(cc=='-')f=-; cc=getchar();}
while(cc>=''&&cc<='')ret=(ret<<)+(ret<<)+cc-'',cc=getchar();
return ret*f;
}
int main()
{
n=rd();
for(int i=;i<=n;i++)a[i]=rd(),st.insert(a[i]);
m=rd();
for(int i=,x,y;i<=m;i++)
{
cin>>ch;
if(ch[]=='U')
{
x=rd(); y=rd();
x=find(x); y=find(y);
if(x==y)continue;//
if(merge(x,y)==x)st.erase(st.find(a[y]));
else st.erase(st.find(a[x]));
}
if(ch[]=='A'&&ch[]=='')
{
x=rd(); y=rd();
solvetag(x);
// int u=del(x); a[x]+=y;
// st.erase(st.find(a[u])); //如果 x 只有自己,则删除后为空! 则RE
// st.insert(a[merge(u,x)]);
st.erase(st.find(a[find(x)]));
a[x]+=y;
st.insert(a[merge(x,del(x))]);
}
if(ch[]=='A'&&ch[]=='')
{
x=rd(); y=rd();
int u=find(x); lzy[u]+=y; a[u]+=y;
st.erase(st.find(a[u]-y));
st.insert(a[u]);
}
if(ch[]=='A'&&ch[]=='')y=rd(),ad+=y;
if(ch[]=='F'&&ch[]=='')x=rd(),solvetag(x),printf("%d\n",a[x]+ad);
if(ch[]=='F'&&ch[]=='')x=rd(),printf("%d\n",a[find(x)]+ad);
if(ch[]=='F'&&ch[]=='')printf("%d\n",*(--st.end())+ad);
}
return ;
}
但是左偏树也可以做,而且也许是 set 常数太大,两种做法用时相差无几(都很慢,5000ms+);
不过比斜堆多开了一个数组呢。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
int const maxn=3e5+;
int n,m,a[maxn],ls[maxn],rs[maxn],fa[maxn],lzy[maxn],ad,sta[maxn],top,dis[maxn];
multiset<int>st;
char ch[];
int find(int x){while(fa[x])x=fa[x]; return x;}
void pushdown(int x)
{
if(!lzy[x])return;
if(ls[x])lzy[ls[x]]+=lzy[x],a[ls[x]]+=lzy[x];
if(rs[x])lzy[rs[x]]+=lzy[x],a[rs[x]]+=lzy[x];
lzy[x]=;
}
int merge(int x,int y)
{
if(!x||!y)return x+y;
if(a[x]<a[y])swap(x,y);
pushdown(x);
rs[x]=merge(rs[x],y);
fa[rs[x]]=x;
if(dis[ls[x]]<dis[rs[x]])swap(ls[x],rs[x]);
if(rs[x])dis[x]=dis[rs[x]]+;
else dis[x]=;
return x;
}
void solvetag(int x)
{
// x=fa[x]; //从 x 开始,使 x 对儿子没有 lzy 的关联
while(x)sta[++top]=x,x=fa[x];
while(top)pushdown(sta[top]),top--;
}
int del(int x)
{
solvetag(x);
int f=fa[x],k=merge(ls[x],rs[x]);
ls[x]=rs[x]=fa[x]=dis[x]=;
fa[k]=f;
if(ls[f]==x)ls[f]=k;
else rs[f]=k;
return find(k);
}
int rd()
{
int ret=,f=; char cc=getchar();
while(cc<''||cc>''){if(cc=='-')f=-; cc=getchar();}
while(cc>=''&&cc<='')ret=(ret<<)+(ret<<)+cc-'',cc=getchar();
return ret*f;
}
int main()
{
n=rd();
for(int i=;i<=n;i++)a[i]=rd(),st.insert(a[i]);
m=rd();
for(int i=,x,y;i<=m;i++)
{
cin>>ch;
if(ch[]=='U')
{
x=rd(); y=rd();
x=find(x); y=find(y);
if(x==y)continue;//
if(merge(x,y)==x)st.erase(st.find(a[y]));
else st.erase(st.find(a[x]));
}
if(ch[]=='A'&&ch[]=='')
{
x=rd(); y=rd();
solvetag(x);
// int u=del(x); a[x]+=y;
// st.erase(st.find(a[u])); //如果 x 只有自己,则删除后为空! 则RE
// st.insert(a[merge(u,x)]);
st.erase(st.find(a[find(x)]));
a[x]+=y;
st.insert(a[merge(x,del(x))]);
}
if(ch[]=='A'&&ch[]=='')
{
x=rd(); y=rd();
int u=find(x); lzy[u]+=y; a[u]+=y;
st.erase(st.find(a[u]-y));
st.insert(a[u]);
}
if(ch[]=='A'&&ch[]=='')y=rd(),ad+=y;
if(ch[]=='F'&&ch[]=='')x=rd(),solvetag(x),printf("%d\n",a[x]+ad);
if(ch[]=='F'&&ch[]=='')x=rd(),printf("%d\n",a[find(x)]+ad);
if(ch[]=='F'&&ch[]=='')printf("%d\n",*(--st.end())+ad);
}
return ;
}
bzoj 2333 [SCOI2011]棘手的操作 —— 可并堆的更多相关文章
- BZOJ 2333: [SCOI2011]棘手的操作 可并堆 左偏树 set
https://www.lydsy.com/JudgeOnline/problem.php?id=2333 需要两个结构分别维护每个连通块的最大值和所有连通块最大值中的最大值,可以用两个可并堆实现,也 ...
- 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 ..题意概述就不写了,各位老爷如果是看着玩的可以去搜一下,如果是做题找来的也知道题干 ...
- 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 ...
- 【BZOJ】2333: [SCOI2011]棘手的操作
http://www.lydsy.com/JudgeOnline/problem.php?id=2333 题意: 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i], ...
随机推荐
- 05Oracle Database 表空间查看,创建,修改及删除
Oracle Database 表空间查看,创建,修改及删除 查看用户表空间 查看数据库管理员表空间表结构 desc dba_tablespaces; 查询表空间名称从管理员表空间表中 select ...
- 【maven】Description Resource Path Location Type An error occurred while filtering resources TESTVIDEO line
在maven中构建项目的时候发现了如下错误: Description Resource Path Location Type An error occurred while filtering res ...
- elk 6.3.2 搭建
CentOS7和java1.8.0) 然后登陆elastic的官网地址下载ELK组件:https://www.elastic.co/cn/products 我是下载了6.3.0版本的: elast ...
- java几种连接数据库的方法
package bean; import java.sql.Connection;import java.sql.DriverManager; public class jdbcTest { //不同 ...
- 基于服务器版centos7的Hadoop/spark搭建
前提说明: 1.Hadoop与spark是两个独立的框架,只安装spark也可独立运行,spark有自己的调度器(standalone模式): 2.在Hadoop的基础上安装spark就是为了使用ya ...
- 使用Mybatis的逆向工程自动生成代码
1.逆向工程的作用 Mybatis 官方提供了逆向工程,可以针对数据库表自动生成Mybatis执行所需要的代码(包括mapper.xml.Mapper.java.pojo). 2.逆向工程的使用方法 ...
- 微信小程序-template模板
============================= 构建template模板 ============================= 1.分析得出共为 ...
- selectByExampleWithBLOBs-----搜索结果包含大字段类型----搜索结果包含大字段类型
http://www.jb51.net/article/121482.htm mybatis generator 使用方法教程(生成带注释的实体类)
- 50. Spring Boot日志升级篇—log4j【从零开始学Spring Boot】
如果你使用的是spring boot 1.4.0版本的话,那么你可能需要配合以下文章进行学习 90.Spring Boot 1.4 使用log4j错误[从零开始学Spring Boot] Log4j是 ...
- Python学习笔记 (2.2)Python中的字符编码问题及标准数据类型之String(字符串)
Python3中的String类型 首先,Python中没有字符类型,只有字符串类型.单个字符按照长度为1的字符串处理,这对于曾是OIER的我来说有点不适应啊. 字符串的表示方法 最常用的就是用一对双 ...