luogu P3380 【模板】二逼平衡树(分块实现)
题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
- 查询 \(k\) 在区间内的排名
- 查询区间内排名为 \(k\) 的值
- 修改某一位值上的数值
- 查询 \(k\) 在区间内的前驱(前驱定义为严格小于 \(x\),且最大的数,若不存在输出 \(-2147483647\))
- 查询 \(k\) 在区间内的后继(后继定义为严格大于 \(x\),且最小的数,若不存在输出\(2147483647\))
Solution
使用分块通过此题。
我们把一个长度为 \(N\) 的序列分成 \(\sqrt N\) 块,每块大小为 \(\sqrt N\),然后维护每个块的有序性。
对于操作 1,直接遍历区间内的块,统计答案即可。时间复杂度 \(O(\sqrt N)\);
对于操作 2,二分答案,用操作 1 检验答案;时间复杂度 \(O(\sqrt N\log N)\)
对于操作 3,暴力修改,排序维护块内顺序,时间复杂度 \(O(\log \sqrt N)\);
对于操作 4、5,等价于查询该数排名 \(+1/-1\) 的数,转化为操作 2。
这样我们便通过了此题。时间复杂度 \(O(N^{\frac 32}\log N)\),空间复杂度 \(T(N)\)。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int MAXN=50010;
const int MAXE=230;
const int MAXA=(int)1e8;
int n,m,sq;
int sx,sy,sd;
struct point{
int x,y;
friend bool operator<(const point a,const point b){
return a.y<b.y;
}
}a[MAXN];
struct split{
int l,r;
int mininum;
point e[MAXE];
void update(){
sort(e+1,e+(r-l+1)+1);
mininum=e[1].y;
}
void build(point p[MAXN],int L,int R){
if(R>n) R=n;
l=L;r=R;
for(int i=l;i<=r;++i)
e[i-l+1]=p[i];
update();
}
int query(int x){
int left=1,right=(r-l+1),mid,sum=0;
while(left<=right){
mid=(left+right)/2;
if(e[mid].y<x){
sum=mid;
left=mid+1;
}else
right=mid-1;
}
return sum;
}
int que(int left,int right,int x){
int cnt=0;
for(int i=l;i<=r;++i)
if(e[i-l+1].x>=max(l,left)&&e[i-l+1].x<=min(r,right)&&e[i-l+1].y<x) ++cnt;
return cnt;
}
int check(int left,int right,int x){
if(left<=l&&r<=right)
return mininum==x;
for(int i=max(l,left);i<=min(r,right);++i)
if(e[i-l+1].y==x) return 1;
return 0;
}
void change(int x,int d){
for(int i=1;i<=r-l+1;++i)
if(e[i].x==x){
e[i].y=d;
break;
}
update();
}
}s[MAXE];
int len=0;
int getnum(int x){
return (x-1)/sq+1;
}
int rank(int l,int r,int x){
int L=getnum(l),R=getnum(r);
int cnt=0;
for(int i=L+1;i<=R-1;++i)
cnt+=s[i].query(x);
cnt+=s[L].que(l,r,x);
if(L!=R) cnt+=s[R].que(l,r,x);
if(!cnt){
for(int i=L;i<=R;++i)
if(s[i].check(l,r,x))
return cnt+1;
return 1;
}
return cnt+1;
}
int find(int l,int r,int x){
int left=0,right=MAXA,mid,s=0;
while(left<=right){
mid=(left+right)/2;
if(rank(l,r,mid)<=x){
s=mid;
left=mid+1;
}else
right=mid-1;
}
return s;
}
void change(int x,int d){
s[getnum(x)].change(x,d);
}
int findupper(int l,int r,int x){
int rk=rank(l,r,x);
if(rk>r-l+1) return 2147483647;
bool flag=(find(l,r,rk)==x);
return find(l,r,rk+flag);
}
int findlower(int l,int r,int x){
int rk=rank(l,r,x);
if(rk<=1) return -2147483647;
return find(l,r,rk-1);
}
inline int read(){
int x=0; char c;
do c=getchar(); while(c<'0'||c>'9');
while(c>='0'&&c<='9')
x=x*10+c-48,c=getchar();
return x;
}
int main(){
n=read();m=read();sq=sqrt(n);
for(int i=1;i<=n;++i)
a[i]=(point){i,read()};
int cnt=0;
while(cnt<n){
s[++len].build(a,cnt+1,cnt+sq);
cnt+=sq;
}
for(int i=1;i<=m;++i){
sd=read();
switch(sd){
case 1:
sx=read();sy=read();sd=read();
int c;
printf("%d\n",c=rank(sx,sy,sd));
break;
case 2:
sx=read();sy=read();sd=read();
printf("%d\n",find(sx,sy,sd));
break;
case 3:
sx=read();sd=read();
change(sx,sd);
break;
case 4:
sx=read();sy=read();sd=read();
printf("%d\n",findlower(sx,sy,sd));
break;
case 5:
sx=read();sy=read();sd=read();
printf("%d\n",findupper(sx,sy,sd));
break;
default:
break;
}
}
}
luogu P3380 【模板】二逼平衡树(分块实现)的更多相关文章
- P3380 【模板】二逼平衡树(树套树)(线段树套平衡树)
P3380 [模板]二逼平衡树(树套树) 前置芝士 P3369 [模板]普通平衡树 线段树套平衡树 这里写的是线段树+splay(不吸氧竟然卡过了) 对线段树的每个节点都维护一颗平衡树 每次把给定区间 ...
- 洛谷P3380 【模板】二逼平衡树(树套树)(线段树+树状数组)
P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...
- 洛谷 P3380 【模板】二逼平衡树(树套树)-线段树套splay
P3380 [模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数 ...
- 洛谷 P3380 bzoj3196 Tyvj1730 【模板】二逼平衡树(树套树)
[模板]二逼平衡树(树套树) 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 查询k在区间内的排名 查询区间内排名为k的值 修改某一位值上的数值 查询k在 ...
- 【题解】二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730]
[题解]二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730] 传送门:[模板]二逼平衡树(树套树)\([P3380]\) \([BZOJ3196]\) \([TYVJ1730]\) ...
- 【BZOJ 3196】二逼平衡树 线段树套splay 模板题
我写的是线段树套splay,网上很多人写的都是套treap,然而本蒟蒻并不会treap 奉上sth神犇的模板: //bzoj3196 二逼平衡树,支持修改某个点的值,查询区间第k小值,查询区间某个值排 ...
- 「luogu3380」【模板】二逼平衡树(树套树)
「luogu3380」[模板]二逼平衡树(树套树) 传送门 我写的树套树--线段树套平衡树. 线段树上的每一个节点都是一棵 \(\text{FHQ Treap}\) ,然后我们就可以根据平衡树的基本操 ...
- bzoj 3196 && luogu 3380 JoyOI 1730 二逼平衡树 (线段树套Treap)
链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3196 题面; 3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Se ...
- ZJOI2013 K大数查询 和 LG3380【模板】二逼平衡树(树套树)
K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c:如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的 ...
- 【BZOJ-3196】二逼平衡树 线段树 + Splay (线段树套平衡树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2271 Solved: 935[Submit][Stat ...
随机推荐
- 误删除系列一:linux的bin目录误删除后恢复操作
感言:一失足成千古恨,一不小心就把/usr/bin下所有的命令都删除了,当你以为自己很熟练时,当你以为自己操作对时,可能就是失手的时候,还好这次只是一个测试环境....God 恢复过程:(以下是在vs ...
- airflow + CeleryExecutor 环境搭建
airflow整合环境搭建 1. 整体结构 mysql -> 后端数据库 redis -> 用于broker CeleryExecutor -> 执行器 2. 环境安装 2.1,安装 ...
- 基于Arduino和Blynk平台的远程控制智能小车
/------转载请附上本文链接 https://i.cnblogs.com/EditArticles.aspx?opt=1 -------啦啦啦我是快乐的分割线- ------------/ 小车图 ...
- vscode主题安装
安装主题 快捷键Ctrl+Shift+X打开安装插件 搜索Monokai ST3 切换主题 显示效果 安装文件图标 扩展插件vscode-icon 鼠标滚轮设置字体大小 打开setting.json文 ...
- mysql8.0版本忘记root密码
1.先关掉系统服务 net stop mysql 2.进入mysql安装目录的bin文件中,以管理员的方式运行cmd,然后输入如下命令,实现无密码登陆 mysqld --console --skip- ...
- Android MediaPlayer 音频倍速播放,调整播放速度
本文链接: Android MediaPlayer 倍速播放,调整播放速度 现在市面上的很多音视频App都有倍速播放的功能,例如把播放速度调整为0.5.1.5.2倍等等. 从Android API 2 ...
- .Net Core 3.0 gRPC部署问题解决
前言 .Net Core3.0终于如约而至的来了.在3.0中增加了许多东西.也有了许多的变化.今天我们看的就是在3.0中使用gRPC并遇到的问题.gRPC现在可以非常方便简洁的在.Net Core中使 ...
- Java基础系列-深入理解==和equals的区别(一)
一.前言 说到==和equals的问题,面试的时候可能经常被问题到,有时候如果你真的没有搞清楚里边的原因,被面试官一顿绕就懵了,所以今天我们也来彻底了解一下这个知识点. 二.==和equals的作用 ...
- SpringBootSecurity学习(04)网页版登录其它授权和登录处理
其它授权配置 security的配置类中,对所有路径进行了统一授权配置.但是有的内容我们也需要让未登录游客有权限访问,比如js,css等静态文件,还有一些宣传页面等等.这些路径可以单独配置: 我们来试 ...
- Spring MVC-从零开始-未完待续
Spring MVC 之 json格式的输入和输出 Spring定时器简单使用 Spring mvc 拦截器的简单使用 Spring MVC文件上传