题目: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. Java基础(五)--内部类

    内部类简单来说就是把一个类的定义放到另一个类的定义内部 内部类分为:成员内部类.局部内部类.匿名内部类.静态内部类 成员内部类:最常见的内部类 public class Outter { privat ...

  2. S-HR之代码创建临时表并插入数据

    ... private String tempTab1 = null; //临时表EcirrWithPPTempTable public String getTempTable() { String ...

  3. background 背景类八大属性

    background 背景类八大属性 背景颜色(当同时定义了背景颜色和背景图像时,背景图像覆盖在背景颜色之上) background-image:背景图像 background-repeat:背景图像 ...

  4. enote笔记语言(2)(ver0.5)

    why not(whyn't)                    为什么不(与“why”相反对应,是它的反面.它的矛盾对立面)   how对策 how设计   key-memo:         ...

  5. Python数据分析与展示(1)-数据分析之表示(2)-NumPy数据存取与函数

    NumPy数据存取与函数 数据的CSV文件存取 CSV文件 CSV(Comma-Separated Value,逗号分隔值) CSV是一种常见的文件格式,用来存储批量数据. 将数据写入CSV文件 np ...

  6. 洛谷 2449 [SDOI2005]矩形

    [题解] 因为这道题中n比较小,n^2效率是可以接受的. 枚举两个矩形,如果它们有重叠部分,就用并查集合并一下即可. #include<cstdio> #include<algori ...

  7. PAT 1142 Maximal Clique

    A clique is a subset of vertices of an undirected graph such that every two distinct vertices in the ...

  8. Prüfer序列和cayley定理

    参考资料: 1.matrix67 <经典证明:Prüfer编码与Cayley公式> 2.百度百科 3.Forget_forever prufer序列总结 4.维基百科 5.dirge的学习 ...

  9. HDU 1234 简单模拟题

    题目很简单不多说了,我只是觉得这题目的输入方式还是很有特点的 #include <cstdio> #include <cstring> #include <algorit ...

  10. [luoguP1403] [AHOI2005]约数研究(这。。。)

    传送门 用类似筛法的原理,就好啦 ——代码 #include <cstdio> int n, ans; int a[1000001]; int main() { int i, j; sca ...