P3380 【模板】二逼平衡树(树套树)
思路
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继
树套树
区间操作可以用我们熟悉的线段树
线段树上每个点 维护对应区间[l,r]的一颗平衡树
线段树深度logn,每层要维护n个节点,所以treap的内存是nlogn
操作2的话,二分顺便用操作1check就好
二分的答案一定是在序列中的 ,复杂度\(log^{3}n\)(真的2b啊,什么复杂度)
其他具体操作就不啰嗦了(复杂度普遍\(log^{2}n\))
而n=5e4的时候\(log^{2}n\)和\(\sqrt{n}\)基本是相等的(分界线)
注意
线段树套平衡树
平衡树的种类也要选好
fhq-treap这种常数就比较大
普通treap就不错
splay也阔以
fhq-treap代码
#include <bits/stdc++.h>
#define FOR(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int maxn=5e4+7;
const int inf=0x7fffffff;
inline int read() {
	int x=0,f=1;char s=getchar();
	for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
	for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
	return x*f;
}
int w[maxn];
int ch[maxn*40][2],val[maxn*40],pri[maxn*40],siz[maxn*40],cnt;
namespace fhq_treap {
	void pushup(int x) {
		siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
	}
	int new_node(int x) {
		val[++cnt]=x;
		pri[cnt]=rand();
		siz[cnt]=1;
		return cnt;
	}
	int merge(int x,int y) {
		if(!x||!y) return x+y;
		if(pri[x]<pri[y]) {
			ch[x][1]=merge(ch[x][1],y);
			pushup(x);return x;
		} else {
			ch[y][0]=merge(x,ch[y][0]);
			pushup(y);return y;
		}
	}
	void split(int now,int k,int &x,int &y) {
		if(!now) x=y=0;
		else {
			if(val[now]<=k)
				x=now,split(ch[now][1],k,ch[x][1],y);
			else
				y=now,split(ch[now][0],k,x,ch[y][0]);
			pushup(now);
		}
	}
	int find(int &rt,int a) {
		int x,y;
		split(rt,a-1,x,y);
		int tmp=siz[x];
		rt=merge(x,y);
		return tmp;
	}
	int k_th(int now,int k) {
		if(siz[now]<k||siz[now]==0||k==0) return 0x7fffffff;
		while(233) {
			if(siz[ch[now][0]]+1==k) return val[now];
			if(siz[ch[now][0]]>=k) now=ch[now][0];
			else k-=siz[ch[now][0]]+1,now=ch[now][1];
		}
	}
	void insert(int &rt,int a) {
		int x,y;
		split(rt,a,x,y);
		rt=merge(merge(x,new_node(a)),y);
	}
	void delet(int &rt,int a) {
		int x,y,z;
		split(rt,a,x,z);
		split(x,a-1,x,y);
		y=merge(ch[y][0],ch[y][1]);
		rt=merge(merge(x,y),z);
	}
	int qq(int &rt,int a) {
		int x,y,tmp;
		split(rt,a-1,x,y);
		tmp=k_th(x,siz[x]);
		rt=merge(x,y);
		return tmp==inf ? -inf : tmp;
	}
	int hj(int &rt,int a) {
		int x,y,tmp;
		split(rt,a,x,y);
		tmp=k_th(y,1);
		rt=merge(x,y);
		return tmp;
	}
}
struct node {
	int l,r,rt;
}e[maxn<<2];
void build(int l,int r,int rt) {
	e[rt].l=l,e[rt].r=r;
	FOR(i,l,r) fhq_treap::insert(e[rt].rt,w[i]);
	if(l==r) return;
	int mid=(l+r)>>1;
	build(l,mid,rt<<1);
	build(mid+1,r,rt<<1|1);
}
void modify(int L,int k,int rt) {
	fhq_treap::delet(e[rt].rt,w[L]);
	fhq_treap::insert(e[rt].rt,k);
	if(e[rt].l==e[rt].r) return;
	int mid=(e[rt].l+e[rt].r)>>1;
	if(L<=mid) modify(L,k,rt<<1);
	else modify(L,k,rt<<1|1);
}
int find(int L,int R,int k,int rt) {
	if(L<=e[rt].l&&e[rt].r<=R)
		return fhq_treap::find(e[rt].rt,k);
	int mid=(e[rt].l+e[rt].r)>>1,ans=0;
	if(L<=mid) ans+=find(L,R,k,rt<<1);
	if(R>mid)  ans+=find(L,R,k,rt<<1|1);
	return ans;
}
int qq(int L,int R,int a,int rt) {
	if(L<=e[rt].l&&e[rt].r<=R) {
		return fhq_treap::qq(e[rt].rt,a);
	}
	int mid=(e[rt].l+e[rt].r)>>1,ans=-inf;
	if(L<=mid) ans=max(ans,qq(L,R,a,rt<<1));
	if(R>mid) ans=max(ans,qq(L,R,a,rt<<1|1));
	return ans;
}
int hj(int L,int R,int a,int rt) {
	if(L<=e[rt].l&&e[rt].r<=R) {
		return fhq_treap::hj(e[rt].rt,a);
	}
	int mid=(e[rt].l+e[rt].r)>>1,ans=inf;
	if(L<=mid) ans=min(ans,hj(L,R,a,rt<<1));
	if(R>mid) ans=min(ans,hj(L,R,a,rt<<1|1));
	return ans;
}
int main() {
	srand(time(NULL));
	int n=read(),m=read();
	FOR(i,1,n) w[i]=read();
	build(1,n,1);
	FOR(i,1,m) {
		int opt=read();
		if(opt==1) {
			int l=read(),r=read(),k=read();
			cout<<find(l,r,k,1)+1<<"\n";
		} else
		if(opt==2) {
			int l=read(),r=read(),k=read();
			int L=0,R=1e8+5,ans=0;
			while(L<=R) {
				int mid=(L+R)>>1;
				if(find(l,r,mid,1)+1<=k) ans=mid,L=mid+1;
				else R=mid-1;
			}
			cout<<ans<<"\n";
		} else
		if(opt==3) {
			int pos=read(),k=read();
			modify(pos,k,1);
			w[pos]=k;
		} else
		if(opt==4) {
			int l=read(),r=read(),k=read();
			cout<<qq(l,r,k,1)<<"\n";
		} else
		if(opt==5) {
			int l=read(),r=read(),k=read();
			cout<<hj(l,r,k,1)<<"\n";
		}
	}
	return 0;
}
P3380 【模板】二逼平衡树(树套树)的更多相关文章
- bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)
		3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1807 Solved: 772[Submit][Stat ... 
- bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)
		3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MB[Submit][Status][Discuss] Description ... 
- BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)
		我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ... 
- BZOJ3196 二逼平衡树  【线段树套平衡树】
		题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱 ... 
- BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay
		传送门 题意 给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种: 查询 $ k $ 在区间 $ [l,r] $ 内的排名 查询区间 $ [l,r] $ 内排 ... 
- [BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)
		传送门 至少BZOJ过了,其他的直接弃. 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的 ... 
- bzoj 3196 Tyvj 1730 二逼平衡树【线段树 套 splay】
		四舍五入就是个暴力. 对于线段树的每个区间都开一棵按权值排序的splay 对于第二个操作,二分一下,每次查询mid的排名,复杂度 $ O(nlog(n)^{3}) $ 其余的操作都是$ O(nlog( ... 
- P3380 【模板】二逼平衡树(树套树)(线段树套平衡树)
		P3380 [模板]二逼平衡树(树套树) 前置芝士 P3369 [模板]普通平衡树 线段树套平衡树 这里写的是线段树+splay(不吸氧竟然卡过了) 对线段树的每个节点都维护一颗平衡树 每次把给定区间 ... 
- 洛谷P3380 【模板】二逼平衡树(树套树)(线段树+树状数组)
		P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ... 
- 洛谷 P3380 【模板】二逼平衡树(树套树)-线段树套splay
		P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ... 
随机推荐
- DOS命令下映射虚拟磁盘(驱动器)
			---恢复内容开始--- subst命令,用于路径替换,进入dos窗口,键入“subst /?”(t和/之间有空格),会看到关于subst的用法如下: C:\Users\Administrator&g ... 
- idea如何整理代码格式
			1.先CRTL + A来选中需要整理的代码块.当然CRTL + A代表选中一个文件的所有代码. 2.然后CRTL + ALT + L,对,就是要记住这个快捷键. 
- linux 下nginx
			所有的配置文件都在/etc/nginx (ect/nginx/nginx.conf) 下,并且每个虚拟主机已经安排在 了/etc/nginx/sites-avail ... 
- 转自大神的KM想法
			我第一次理解KM算法看到大神的讲解不胜感激这km挺神奇的接下来就见识一下这个大牛的吧 转自 http://blog.csdn.net/wuxinxiaohuangdou/article/details ... 
- jQuery工具--jQuery.isNumeric(value)和jQuery.trim(str)
			jQuery.isNumeric(value) 概述 确定它的参数是否是一个数字. $.isNumeric() 方法检查它的参数是否代表一个数值.如果是这样,它返回 true.否则,它返回false. ... 
- Lua 服务器Socket通信实例
			local socket = require"socket" local host = "127.0.0.1"local port = "843&qu ... 
- Saiku + Kylin 多维分析平台探索
			背景 为了应对各种数据需求,通常,我们的做法是这样的: 对于临时性的数据需求:写HQL到Hive里去查一遍,然后将结果转为excel发送给需求人员. 对于周期性的.长期性的数据需求:编写脚本,结合Hi ... 
- mybatis源码解析5---SqlSession解析
			由之前解析可知,mybatis启动的时候会加载XML配置文件解析生成全局配置对象Configuration对象,SqlSessionFactoryBuilder类会根据Configuration对象创 ... 
- pcb走线注意事项笔记
			一.高压隔离. PCB的安全距离: 1.电气间隙或者叫做控件距离. (两相邻的后者一个到相邻电机壳表面的沿空气测量的最短距离,电气间隙的决定,根据测量的工作电压以及绝缘等级就可以决定距离.) a.一次 ... 
- 前端框架VUE----指令
			一.什么是VUE? 它是构建用户界面的JavaScript框架(让它自动生成js,css,html等) 二.怎么使用VUE? 1.引入vue.js 2.展示HTML <div id=" ... 
