题目: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]棘手的操作 —— 可并堆的更多相关文章

  1. BZOJ 2333: [SCOI2011]棘手的操作 可并堆 左偏树 set

    https://www.lydsy.com/JudgeOnline/problem.php?id=2333 需要两个结构分别维护每个连通块的最大值和所有连通块最大值中的最大值,可以用两个可并堆实现,也 ...

  2. BZOJ 2333 [SCOI2011]棘手的操作 (可并堆)

    码农题.. 很显然除了两个全局操作都能用可并堆完成 全局最大值用个multiset记录,每次合并时搞一搞就行了 注意使用multiset删除元素时 如果直接delete一个值,会把和这个值相同的所有元 ...

  3. BZOJ 2333: [SCOI2011]棘手的操作

    题目描述 真的是个很棘手的操作.. 注意每删除一个点,就需要clear一次. #include<complex> #include<cstdio> using namespac ...

  4. BZOJ 2333 SCOI2011 棘手的操作 并查集+可并堆

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2333 ..题意概述就不写了,各位老爷如果是看着玩的可以去搜一下,如果是做题找来的也知道题干 ...

  5. 2333: [SCOI2011]棘手的操作[写不出来]

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

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

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

  7. 2333: [SCOI2011]棘手的操作[我不玩了]

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

  8. 【bzoj2333】 [SCOI2011]棘手的操作 可并堆+lazy标记

    2016-05-31  21:45:41 题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2333 (学习了黄学长的代码 有如下操作: U x y ...

  9. 【BZOJ】2333: [SCOI2011]棘手的操作

    http://www.lydsy.com/JudgeOnline/problem.php?id=2333 题意: 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i], ...

随机推荐

  1. IDEA SpringBoot项目连接数据库报Acess denied错误解决方法

    详见:https://blog.csdn.net/qq_36324464/article/details/79534605

  2. java.lang.NoSuchFieldError: DEFAULT_INCOMPATIBLE_IMPROVEMENTS

    解决方案: 启动类上加@EnableAutoConfiguration(exclude = { FreeMarkerAutoConfiguration.class }) 或者在配置文件添加spring ...

  3. canvas练手项目(三)——Canvas中的Text文本

    Canvas中的Text文本也是一个知识点~,我们需要掌握一下几个基本的Text操作方法 首先是重要参数textAlign和textBaseline: textAlign left center ri ...

  4. vue父子通信的基本使用

    项目中没怎么用过父子通信,很多页面都是路由切换实现的,后来做首页的时候发现首页的路径没法配置,我强行在原先的首页上写了个子组件,通过判断路径使其强行跳转实现的 这个时候跳转页面的时候就要使用到了父子间 ...

  5. 移动端开发需要加的meta

    移动端开发需要加的meta和常用的css3媒体查询样式,移动开发中头部要加的一些常用meta. <meta name="viewport" content="ini ...

  6. 大理石在哪儿(Where is the Marble?,Uva 10474)

    现有N个大理石,每个大理石上写了一个非负整数.首先把各数从小到大排序,然后回 答Q个问题.每个问题问是否有一个大理石写着某个整数x,如果是,还要回答哪个大理石上 写着x.排序后的大理石从左到右编号为1 ...

  7. ACM多校联赛7 2018 Multi-University Training Contest 7 1009 Tree

    [题意概述] 给一棵以1为根的树,树上的每个节点有一个ai值,代表它可以传送到自己的ai倍祖先,如果不存在则传送出这棵树.现在询问某个节点传送出这棵树需要多少步. [题解] 其实是把“弹飞绵羊”那道题 ...

  8. 洛谷 1803 凌乱的yyy

    [题意概述] 给出100W个区间,要求找出尽量多的区间满足它们互补重叠,输出最大的区间数. [题解] 贪心. 对区间按照右端点从小到大排序,然后逐个加入合法区间即可. #include<cstd ...

  9. 洛谷 1984 [SDOI2008]烧水问题

    [题解] 烧开每一杯水之后都用它去把其他没烧开的水焐热,这样显然是最优的.然后推推式子或者列表找规律就好了. #include<cstdio> #include<algorithm& ...

  10. 关于markdown(typora)的操作指南,以及导出为word格式文件插件(pandoc-2.6-windows-x86_64)的下载

    Markdown简介 插件链接文章结尾处 目录 Markdown简介1. Markdown是什么?2. 谁创造了它?3. 为什么要使用它?4. 怎么使用?4.1 标题4.2 段落4.3 区块引用4.4 ...