题目: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. 并发和多线程(三)--并发容器J.U.C和lock简介

    AQS: 是AbstractQueuedSynchronizer的简称,JUC的核心 底层是sync queue双向链表,还可能有condition queue单向链表,使用Node实现FIFO队列, ...

  2. 【原】Mysql常用语句

    1.修改编码方式为UTF-8 ALTER   TABLE   表名  CHANGE  列名  新列名  VARCHAR(255)    CHARACTER  SET  utf8  COLLATE    ...

  3. TestNG套件测试(二)

    在xml中指定要运行的整个包来执行套件测试 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ...

  4. swiper.animate--css3翻页动画

    基于swiper 的 animate动画,适用于Swiper2.x和Swiper3.x . 1. 使用Swiper Animate需要先加载swiper.animate.min.js和animate. ...

  5. CF441D

    题目大意 给出一个有n个数的序列 求符合 区间各数或起来的数大于区间最大数 的区间的个数 题解 预处理出每个数每一位是0的那位左边最近的1和右边最近的1,用单调栈找出每个最大值所在的区间的左右端点,统 ...

  6. hdu 1166敌兵布阵(线段树入门题)

    >>点击进入原题测试<< 思路:这两天在学线段树,这个题直接手敲一下线段树就行了,都没有用上懒人标记.入门题 cin,cout会超时,记得加std::ios::sync_wit ...

  7. ssc项目Python爬虫心得

    ###今日心得 ####time.datetime 1.字符串格式到标准化格式:time.strptime(str, "%Y%m%d") 2.今天的标准化格式:today = da ...

  8. COJ 1411 Longest Consecutive Ones

    题目大意: 希望在 k 步之内,将尽可能多的1移到相邻的位置上 这里依靠前缀和解决问题 我们用pos[i]保存第i个1的位置,这里位置我以1开始 用sum[i]保存前 i 个1从 0 点移到当前位置所 ...

  9. MQTT---HiveMQ源代码具体解释(一)概览

    源博客地址:http://blog.csdn.net/pipinet123 MQTT交流群:221405150 面向群体 想自己实现MQTT Broker的朋友 对现有开源的MQTT Broker或多 ...

  10. ORA-01925:maximum of 80 enabled roles exceeded

    ORA-01925:maximum of 80 enabled roles exceeded max_enabled_roles 9i的參数,10g及以后都不用了. 指定用户session的最大ena ...