[学习笔记]树套树 线段树套Splay
今天调了一个早上哈哈哈,不过因为\(Splay\),常数比较大
洛谷的评测记录:

\(Code\ Below:\)
#include <bits/stdc++.h>
#define ll long long
#define mid (l+r>>1)
using namespace std;
const int maxn=4000010;
const int inf=2147483647;
int n,m,sz,ans,Max;
int a[maxn],ch[maxn][2],fa[maxn],siz[maxn],cnt[maxn],key[maxn],rt[maxn];
inline void splayclear(int x){
fa[x]=ch[x][0]=ch[x][1]=siz[x]=cnt[x]=key[x]=0;
}
inline bool get(int x){
return ch[fa[x]][1]==x;
}
inline void update(int x){
siz[x]=(ch[x][0]?siz[ch[x][0]]:0)+(ch[x][1]?siz[ch[x][1]]:0)+cnt[x];
}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=get(x);
ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
ch[x][k^1]=y;fa[y]=x;fa[x]=z;
if(z) ch[z][ch[z][1]==y]=x;
update(y);update(x);
}
inline void splay(int i,int x,int top){
for(int y,z;fa[x]!=top;rotate(x)){
y=fa[x],z=fa[y];
if(z!=top) rotate(get(x)==get(y)?y:x);
}
if(!top) rt[i]=x;
}
inline void splayinsert(int i,int val){
int x=rt[i],y;
if(!rt[i]){
rt[i]=x=++sz;fa[x]=ch[x][0]=ch[x][1]=0;
key[x]=val;siz[x]=cnt[x]=1;return;
}
while(1){
if(key[x]==val){cnt[x]++;update(y);break;}
y=x;x=ch[x][key[x]<val];
if(x==0){
x=++sz;key[x]=val;siz[x]=cnt[x]=1;
ch[y][key[y]<val]=x;fa[x]=y;
update(y);break;
}
}
splay(i,x,0);
}
inline int splayrank(int i,int val){
int x=rt[i],ret=0;
while(x>0){
if(val<key[x]) x=ch[x][0];
else {
ret+=(ch[x][0]?siz[ch[x][0]]:0);
if(val==key[x]) return ret;
ret+=cnt[x];x=ch[x][1];
}
}
return ret;
}
inline int splayfind(int i,int val){
int x=rt[i];
while(x>0){
if(val==key[x]){splay(i,x,0);return x;}
x=ch[x][key[x]<val];
}
}
inline int splaypre(int i){int x=ch[rt[i]][0];while(ch[x][1])x=ch[x][1];return x;}
inline int splaysuc(int i){int x=ch[rt[i]][1];while(ch[x][0])x=ch[x][0];return x;}
inline void splaydel(int i,int val){
int x=splayfind(i,val),y=rt[i];
if(cnt[x]>1){cnt[x]--;update(x);return;}
if(!ch[x][0]&&!ch[x][1]){splayclear(rt[i]);rt[i]=0;return;}
if(!ch[x][0]){y=ch[x][1];rt[i]=y;fa[y]=0;return;}
if(!ch[x][1]){y=ch[x][0];rt[i]=y;fa[y]=0;return;}
splay(i,splaypre(i),0);
ch[rt[i]][1]=ch[y][1];fa[ch[y][1]]=rt[i];
splayclear(y);update(rt[i]);
}
inline int splaygetpre(int i,int val){
int x=rt[i];
while(x>0){
if(val<=key[x]) x=ch[x][0];
else {
if(key[x]>ans) ans=key[x];
x=ch[x][1];
}
}
return ans;
}
inline int splaygetsuc(int i,int val){
int x=rt[i];
while(x>0){
if(val>=key[x]) x=ch[x][1];
else {
if(key[x]<ans) ans=key[x];
x=ch[x][0];
}
}
return ans;
}
inline void seginsert(int l,int r,int rt,int x,int val){
splayinsert(rt,val);
if(l == r) return;
if(x <= mid) seginsert(l,mid,rt<<1,x,val);
else seginsert(mid+1,r,rt<<1|1,x,val);
}
inline void segrank(int L,int R,int val,int l,int r,int rt){
if(L <= l && r <= R){ans+=splayrank(rt,val);return;}
if(L <= mid) segrank(L,R,val,l,mid,rt<<1);
if(R > mid) segrank(L,R,val,mid+1,r,rt<<1|1);
}
inline void segchange(int l,int r,int rt,int x,int val){
splaydel(rt,a[x]);splayinsert(rt,val);
if(l == r){a[x]=val;return;}
if(x <= mid) segchange(l,mid,rt<<1,x,val);
else segchange(mid+1,r,rt<<1|1,x,val);
}
inline void segpre(int L,int R,int val,int l,int r,int rt){
if(L <= l && r <= R){ans=max(ans,splaygetpre(rt,val));return;}
if(L <= mid) segpre(L,R,val,l,mid,rt<<1);
if(R > mid) segpre(L,R,val,mid+1,r,rt<<1|1);
}
inline void segsuc(int L,int R,int val,int l,int r,int rt){
if(L <= l && r <= R){ans=min(ans,splaygetsuc(rt,val));return;}
if(L <= mid) segsuc(L,R,val,l,mid,rt<<1);
if(R > mid) segsuc(L,R,val,mid+1,r,rt<<1|1);
}
inline int getkth(int L,int R,int k){
int l=0,r=Max+1,Mid;
while(l<r){
Mid=l+r>>1;ans=0;
segrank(L,R,Mid,1,n,1);
if(ans<k) l=Mid+1;
else r=Mid;
}
return l-1;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
seginsert(1,n,1,i,a[i]);
Max=max(Max,a[i]);
}
int opt,l,r,val;
while(m--){
scanf("%d%d%d",&opt,&l,&r);
switch(opt){
case 1:scanf("%d",&val);ans=0;segrank(l,r,val,1,n,1);printf("%d\n",ans+1);break;
case 2:scanf("%d",&val);printf("%d\n",getkth(l,r,val));break;
case 3:segchange(1,n,1,l,r);break;
case 4:scanf("%d",&val);ans=-inf;segpre(l,r,val,1,n,1);printf("%d\n",ans);break;
case 5:scanf("%d",&val);ans=inf;segsuc(l,r,val,1,n,1);printf("%d\n",ans);break;
}
}
return 0;
}
[学习笔记]树套树 线段树套Splay的更多相关文章
- ACM学习笔记:可持久化线段树
title : 可持久化线段树 date : 2021-8-18 tags : 数据结构,ACM 可持久化线段树 可以用来解决线段树存储历史状态的问题. 我们在进行单点修改后,线段树只有logn个(一 ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
- BZOJ 3218(a + b Problem-二分图套值域线段树)
出这题的人是怎么想出来的…… 言归正传,这题是二分图套值域线段树. 首先经过 @Vfleaking的神奇建图后,把图拆成二分图, 不妨利用有向图最小割的性质建图(以前我一直以为最小割和边的方向无关,可 ...
- [BZOJ1146][CTSC2008]网络管理Network(二分+树链剖分+线段树套平衡树)
题意:树上单点修改,询问链上k大值. 思路: 1.DFS序+树状数组套主席树 首先按照套路,关于k大值的问题,肯定要上主席树,每个点维护一棵权值线段树记录它到根的信息. 关于询问,就是Que(u)+Q ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- UOJ#30/Codeforces 487E Tourists 点双连通分量,Tarjan,圆方树,树链剖分,线段树
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ30.html 题目传送门 - UOJ#30 题意 uoj写的很简洁.清晰,这里就不抄一遍了. 题解 首先建 ...
- 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex
题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...
- BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树
题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...
- 树状数组 && 线段树应用 -- 求逆序数
参考:算法学习(二)——树状数组求逆序数 .线段树或树状数组求逆序数(附例题) 应用树状数组 || 线段树求逆序数是一种很巧妙的技巧,这个技巧的关键在于如何把原来单纯的求区间和操作转换为 求小于等于a ...
- 差分+树状数组 线段树【P2357】 守墓人
题目描述-->p2357 守墓人 敲了一遍线段树,水过. 树状数组分析 主要思路: 差分 简单介绍一下差分(详细概念太麻烦,看下面. 给定一个数组 7 8 6 5 1 8 18 20 35 // ...
随机推荐
- 【Web】Nginx 反向代理与负载均衡
反向代理 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客 ...
- JS高级-String- RegExp- Math- Date:
1. String: 切割: 将一个字符串,按指定分隔符,切割为多段子字符串 简单切割: 切割符是固定的 var arr=str.split("切割符") 强调: 切割后的结果中, ...
- Java第15章笔记
字符串的概述 1.什么是字符串:零个或多个字符组成的有限序列 2.如何使用字符串:(使用字符串分为两步) 1)定义并初始化字符串 2)使用字符,对字符串进行一些处理 ...
- js 判断 undefined,单选 以及下拉框选中状态
name = $(this).attr("title"); if(typeof(name) == 'undefined'){ alert(1); } typeof 函数 radio ...
- linux 安装 ORACLE JDK 8
1.卸载默认的OPENJDK 查看 open jdk 的安装 rpm -qa | grep java 卸载 openjdk rpm -e --nodeps java-1.7.0-openjdk-1.7 ...
- linux系统配置参数修改
一.永久修改主机名修改/etc/sysconfig/network,在里面指定主机名称HOSTNAME=然后执行命令hostname 主机名这个时候可以注销一下系统,再重登录之后就行了. 或者修改/e ...
- 第05章:MongoDB-CRUD操作--数据库
①显示现有的数据库 命令:show dbs 或者databases; ②显示当前的数据库 命令:db ③使用|创建数据库 命令:use 数据库名称 如果数据库不存在,则创建数据库,否则切换到指定数 ...
- querySelectorAll()方法
querySelectorAll()方法 调用的对象包括:Document(文档) DocumentFragment(文档片段) Element(元素) querySelectorAll()方法接收的 ...
- JS中的计时器事件
JS可以实现很多java代码不易完成的功能.这里学习一些js中的计时器事件. JavaScript 一个设定的时间间隔之后来执行代码,称之为计时事件. 主要通过两个方法来实现: 1.setInterv ...
- Redis-环境搭建
Redis官方不提供Windows版,不过微软开源组织提供了Windows版本的Redis,此处将安装Windows版的Reids,供学习使用. 1.下载Windows版Redis安装包: 安装包地址 ...