【bzoj3196】Tyvj 1730 二逼平衡树 线段树套Treap
题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
输入
第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若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的后继
输出
对于操作1,2,4,5各输出一行,表示查询结果
样例输入
9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5
样例输出
2
4
3
4
9
题解
树套树,外层线段树内层Treap
对于外层线段树的每个节点,在此之上建立一棵Treap。
这样用外层线段树维护区间,内层Treap维护排名,能够轻松处理出询问1、3、4、5。
具体地,1操作在线段树中不断查找区间,在线段树节点对应的Treap中查找有多少个比k小的,类似于普通线段树的区间查询。4、5操作同理。
3操作在线段树中不断查找区间,在线段树节点对应的Treap中删除原数,添加新数,类似于普通线段树的单点修改。
然而仅仅是这样并不能处理出2操作。
考虑到查某排名的数很不容易,但查某数的排名比较简单(操作1),于是我们可以二分答案,并用操作1的方法判断即可。
1、3、4、5操作时间复杂度O(log^2n),2操作时间复杂度O(log^3n)。
常数已经优化到比较小了,亲测在某些卡时间的oj上可以过。
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#define N 200010
#define M 4000010
#define inf 0x7fffffff
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
using namespace std;
int n , v[N] , root[N] , w[M] , cnt[M] , si[M] , ls[M] , rs[M] , rnd[M] , tot;
void pushup(int k)
{
si[k] = si[ls[k]] + si[rs[k]] + cnt[k];
}
void zig(int &k)
{
int t = ls[k];
ls[k] = rs[t] , rs[t] = k , si[t] = si[k] , pushup(k) , k = t;
}
void zag(int &k)
{
int t = rs[k];
rs[k] = ls[t] , ls[t] = k , si[t] = si[k] , pushup(k) , k = t;
}
void ins(int &k , int a)
{
if(!k)
{
k = ++tot , w[k] = a , cnt[k] = si[k] = 1 , rnd[k] = rand();
return;
}
si[k] ++ ;
if(a == w[k]) cnt[k] ++ ;
else if(a < w[k])
{
ins(ls[k] , a);
if(rnd[ls[k]] < rnd[k]) zig(k);
}
else
{
ins(rs[k] , a);
if(rnd[rs[k]] < rnd[k]) zag(k);
}
}
void del(int &k , int a)
{
if(a == w[k])
{
if(cnt[k] > 1) cnt[k] -- , si[k] -- ;
else if(!ls[k] || !rs[k]) k = ls[k] + rs[k];
else if(rnd[ls[k]] < rnd[rs[k]]) zig(k) , del(k , a);
else zag(k) , del(k , a);
}
else if(a < w[k]) del(ls[k] , a) , si[k] -- ;
else del(rs[k] , a) , si[k] -- ;
}
int getless(int k , int a)
{
if(!k) return 0;
if(a <= w[k]) return getless(ls[k] , a);
else return getless(rs[k] , a) + si[ls[k]] + cnt[k];
}
int getpro(int k , int a)
{
if(!k) return 0;
if(a <= w[k]) return getpro(ls[k] , a);
else return max(w[k] , getpro(rs[k] , a));
}
int getsub(int k , int a)
{
if(!k) return inf;
if(a >= w[k]) return getsub(rs[k] , a);
else return min(w[k] , getsub(ls[k] , a));
}
void build(int l , int r , int x)
{
int i , mid = (l + r) >> 1;
for(i = l ; i <= r ; i ++ ) ins(root[x] , v[i]);
if(l == r) return;
build(lson) , build(rson);
}
void update(int p , int a , int l , int r , int x)
{
del(root[x] , v[p]) , ins(root[x] , a);
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) update(p , a , lson);
else update(p , a , rson);
}
int queryless(int b , int e , int a , int l , int r , int x)
{
if(b <= l && r <= e) return getless(root[x] , a);
int mid = (l + r) >> 1 , ans = 0;
if(b <= mid) ans += queryless(b , e , a , lson);
if(e > mid) ans += queryless(b , e , a , rson);
return ans;
}
int querypro(int b , int e , int a , int l , int r , int x)
{
if(b <= l && r <= e) return getpro(root[x] , a);
int mid = (l + r) >> 1 , ans = 0;
if(b <= mid) ans = max(ans , querypro(b , e , a , lson));
if(e > mid) ans = max(ans , querypro(b , e , a , rson));
return ans;
}
int querysub(int b , int e , int a , int l , int r , int x)
{
if(b <= l && r <= e) return getsub(root[x] , a);
int mid = (l + r) >> 1 , ans = inf;
if(b <= mid) ans = min(ans , querysub(b , e , a , lson));
if(e > mid) ans = min(ans , querysub(b , e , a , rson));
return ans;
}
int solvenum(int b , int e , int a)
{
int l = querysub(b , e , -1 , 1 , n , 1) , r = querypro(b , e , inf , 1 , n , 1) , mid , ans = 0;
while(l <= r)
{
mid = (l + r) >> 1;
if(queryless(b , e , mid , 1 , n , 1) + 1 <= a) ans = mid , l = mid + 1;
else r = mid - 1;
}
return ans;
}
int main()
{
int m , i , opt , x , y , z;
scanf("%d%d" , &n , &m);
for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &v[i]);
build(1 , n , 1);
while(m -- )
{
scanf("%d%d%d" , &opt , &x , &y);
if(opt != 3) scanf("%d" , &z);
switch(opt)
{
case 1: printf("%d\n" , queryless(x , y , z , 1 , n , 1) + 1); break;
case 2: printf("%d\n" , solvenum(x , y , z)); break;
case 3: update(x , y , 1 , n , 1) , v[x] = y; break;
case 4: printf("%d\n" , querypro(x , y , z , 1 , n , 1)); break;
default: printf("%d\n" , querysub(x , y , z , 1 , n , 1));
}
}
return 0;
}
【bzoj3196】Tyvj 1730 二逼平衡树 线段树套Treap的更多相关文章
- [bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)
Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在 ...
- BZOJ - 3196 Tyvj 1730 二逼平衡树 (线段树套treap)
题目链接 区间线段树套treap,空间复杂度$O(nlogn)$,时间复杂度除了查询区间k大是$O(log^3n)$以外都是$O(log^2n)$的. (据说线段树套线段树.树状数组套线段树也能过?) ...
- [bzoj3196]Tyvj 1730 二逼平衡树——线段树套平衡树
题目 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查 ...
- bzoj 3196 && luogu 3380 JoyOI 1730 二逼平衡树 (线段树套Treap)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 题面; 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Se ...
- bzoj3196: Tyvj 1730 二逼平衡树 树套树
地址:http://www.lydsy.com/JudgeOnline/problem.php?id=3196 题目: 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec ...
- 【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树
线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/p ...
- BZOJ3196二逼平衡树——线段树套平衡树(treap)
此为平衡树系列最后一道:二逼平衡树您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询 ...
- 【BZOJ 3196】二逼平衡树 线段树套splay 模板题
我写的是线段树套splay,网上很多人写的都是套treap,然而本蒟蒻并不会treap 奉上sth神犇的模板: //bzoj3196 二逼平衡树,支持修改某个点的值,查询区间第k小值,查询区间某个值排 ...
- BZOJ3196: Tyvj 1730 二逼平衡树
传送门 主席树的常数蜜汁优越,在BZOJ上跑了rnk1. 做法很简单,主席树套BIT. 1-3做法很简单,第四个和第五个做法转换成前两个就行了. //BZOJ 3196 //by Cydiater / ...
随机推荐
- Python进阶-函数默认参数
Python进阶-函数默认参数 写在前面 如非特别说明,下文均基于Python3 一.默认参数 python为了简化函数的调用,提供了默认参数机制: def pow(x, n = 2): r = 1 ...
- fopen,fwrite,fread使用
fopen, fwrite, fread详解 1.头文件 #include <stdio.h> 2.fopen (1) 函数原型 FILE *fopen(char *filename, * ...
- Python3爬虫(九) 数据存储之关系型数据库MySQL
Infi-chu: http://www.cnblogs.com/Infi-chu/ 关系型数据库关系型数据库是基于关系模型的数据库,而关系模型是通过二维表来保存的,所以关系型数据库的存储方式就是行列 ...
- go学习笔记-语言指针
语言指针 定义及使用 变量是一种使用方便的占位符,用于引用计算机内存地址.取地址符是 &,放到一个变量前使用就会返回相应变量的内存地址. 一个指针变量指向了一个值的内存地址.类似于变量和常量, ...
- Rmarkdown:输出html设置
在Rstudio中可自行更改主题样式 --- title: "题目" author: "name" date: "`r format(Sys.time ...
- CERC2017 Gambling Guide,最短路变形,期望dp
题意 给定一个无向图,你需要从1点出发到达n点,你在每一点的时候,使用1个单位的代价,随机得到相邻点的票,但是你可以选择留在原地,也可以选择使用掉这张票,问到达n点的最小代价的方案的期望是多少. 分析 ...
- 怎么实现hibernate悲观锁和乐观锁?
隔离级别的安全控制是整体一个大的方面,而锁机制更加的灵活,它执行的粒度可以很小,可以在一个事务中存在. Hibernate悲观锁是依靠底层数据库的锁机制实现,在查询query.setLockMode( ...
- http报文和浏览器缓存机制
目录 1. 请求报文 1.1请求行 1.2 请求头 一些常用的请求头信息 2. 响应报文 2.1 状态行 1> 响应状态码 2> 常见的响应状态码 2.2 响应头 3. 浏览器缓存 3.1 ...
- Delphi实例之一个简易的浏览器的实现
Delphi实例之一个简易的浏览器的实现 Delphi7的WebBrowser组件提供了很多不错的网页设计的功能,下面做一个简单的浏览器.组件很简单按照下面摆放就行了. 这是运行后的效果 源代码 主页 ...
- 【IOI 2002/FJOI2019】任务安排(超级计算机)
题目 \(N\) 个任务排成一个序列在一台机器上等待完成(顺序不得改变),这 \(N\) 个任务被分成若干批,每批包含相邻的若干任务.从时刻 \(0\) 开始,这些任务被分批加工,第 \(i\) 个任 ...