牛客小白月赛18 E.Forsaken的数列【Splay】
时间:2020-04-13
本文章向大家介绍牛客小白月赛18 E.Forsaken的数列【Splay】,主要包括牛客小白月赛18 E.Forsaken的数列【Splay】使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
传送门
之前用 FhqTreap 写过,刚刚学了 splay,再用 splay 写一下。
splay 比 FhqTreap 好的地方就是好写一点,但速度丢人。
splay 处理区间问题,就每次将代表 l-1 位置的点甩到根,然后将代表 r+1 的点甩到根的右儿子,那么此时 r+1 的点的左子树就是要处理的区间。
在指定位置插入数也是一个道理,将 pos-1 甩到根,pos 甩到根的右儿子,把新插入的点设为 pos 的左儿子即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=2e5+10;
int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return x*f;
}
int n,a[N];
struct Splay{
int root,siz[N],fa[N],ch[N][2],tot;LL sum[N],val[N],tag[N];
int newnode(int x,int f){fa[++tot]=f;val[tot]=sum[tot]=x;siz[tot]=1;return tot;}
int relat(int p,int f){return ch[f][1]==p;}
void connect(int p,int f,int k){ch[f][k]=p;fa[p]=f;}
void pushup(int p){
siz[p]=siz[ch[p][0]]+siz[ch[p][1]]+1;
sum[p]=sum[ch[p][0]]+sum[ch[p][1]]+val[p];
}
void pushdown(int id){
int ls=ch[id][0],rs=ch[id][1];
sum[ls]+=tag[id]*siz[ls];val[ls]+=tag[id];tag[ls]+=tag[id];
sum[rs]+=tag[id]*siz[rs];val[rs]+=tag[id];tag[rs]+=tag[id];
tag[id]=0;
}
void rotate(int p){
int f=fa[p],ff=fa[f],k=relat(p,f);
connect(ch[p][k^1],f,k);
connect(p,ff,relat(f,ff));
connect(f,p,k^1);
pushup(f);pushup(p);
}
void splay(int p,int top){
if(top==0) root=p;
while(fa[p]!=top){
int f=fa[p],ff=fa[f];
if(ff!=top) relat(p,f)^relat(f,ff)?rotate(p):rotate(f);
rotate(p);
}
}
int findpos(int k){
int p=root;
while(1){
if(tag[p]) pushdown(p);
if(k<=siz[ch[p][0]]) p=ch[p][0];
else if(k==siz[ch[p][0]]+1) break;
else k-=siz[ch[p][0]]+1,p=ch[p][1];
}
return p;
}
void insert(int k,int x=0){
int p=findpos(k),q=findpos(k+1);
splay(p,0);splay(q,p);
int id=newnode(x,q);
ch[q][0]=id;
splay(id,0);
}
void upd(int l,int r,int x){
int p=findpos(l),q=findpos(r+2);
splay(p,0);splay(q,p);
int id=ch[q][0];
sum[id]+=1ll*x*siz[id];val[id]+=x;tag[id]+=x;
}
LL ask(int l,int r){
int p=findpos(l),q=findpos(r+2);
splay(p,0);splay(q,p);
return sum[ch[q][0]];
}
}spl;
int main(){
n=read();
for(int i=1;i<=n;i++) a[i]=read();
for(int i=0;i<=n+1;i++){
int p=spl.newnode(a[i],i);
if(i) spl.ch[i][1]=p;
spl.splay(p,0);
}
int m=read();
while(m--){
int opt=read();
if(opt==1) {int pos=read();spl.insert(pos);}
else if(opt==2){
int l=read(),r=read(),x=read();
spl.upd(l,r,x);
}
else if(opt==3){
int l=read(),r=read();
printf("%lld\n",spl.ask(l,r));
}
}
return 0;
}
原文地址:https://www.cnblogs.com/BakaCirno/p/12691934.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 微信小程序【浅提WXSS样式】
- Kubernetes Liveness and Readiness Probes
- Magicodes.IE 2.3重磅发布——.NET Core开源导入导出库
- pytest文档59-运行未提交git的用例(pytest-picked)
- pytest文档57-单元测试代码覆盖率(pytest-cov)
- pytest文档58-随机执行测试用例(pytest-random-order)
- Kubernetes探针踩坑记
- 大揭秘| 我司项目组Gitlab Flow && DevOps流程
- 离线安装Superset 0.37(截图详细版)
- 如何高速转储、索引和第7层网络流量过滤?
- 爬虫 | JS逆向某验滑动加密(二)
- 闲聊 Kotlin-Native (0) - 我们为什么应该关注一下 Kotlin Native?
- 哈佛大学单细胞课程|笔记汇总 (五)
- 通过源码理解IGMP v1的实现(基于linux1.2.13)
- 微服务下数据一致性的几种实现方式