题目: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 ;
}

最新文章

  1. 【bzoj1672】[USACO2005 Dec]Cleaning Shifts 清理牛棚
  2. php curl ftp上传 下载
  3. Abp公共连接和事务管理方法
  4. django 模版语法及使用
  5. 再一次见证mssql中in 与exist的区别
  6. C#基础及记忆概念
  7. 八皇后问题 lua版
  8. HDFS文件系统的操作
  9. javascript区分电脑与手机登陆
  10. Linux08--Shell程序设计03 shell script
  11. xhtmlrenderer渲染pdf,中文换行
  12. 1901: Zju2112 Dynamic Rankings
  13. 移动端 canvas插入多张图片生成一张可保存到手机图片
  14. Mysql使用alias 防止对数据的误操作
  15. 与音频相关的技术知识点总结(Linux方向的开发)
  16. #Java学习之路——基础阶段二(第五篇)
  17. Response.Write()方法响应导致页面字体变大的解决办法
  18. [Swift]LeetCode148. 排序链表 | Sort List
  19. ROS笔记2 构建一个package
  20. Vasya And The Mushrooms CodeForces - 1016C (前缀和模拟)

热门文章

  1. Mybatis学习总结三(动态SQL)
  2. 12Java Bean
  3. 充当别的mcu的外部存储器(51类)
  4. java多线程synchronized volatile解析
  5. SQL 快速参考-----http://www.runoob.com/sql/sql-quickref.html
  6. Leetcode 79.单词搜索
  7. noip模拟赛 铺瓷砖
  8. [K/3Cloud]实现双击列表行后显示具体的某个单据明细。
  9. Linux下汇编语言学习笔记77 ---
  10. 20180906关于mysql启动