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 ...
随机推荐
- Webdriver元素定位的方法
webdriver提供了8种元素定位方法: 1.id 2.name 3.tag name 4.class name 5.link text 6.partial link text 7.xpath 8. ...
- sql server之SQL SELECT INTO 语句
SELECT INTO 语句可用于创建表的备份复件. SELECT INTO 语句 SELECT INTO 语句从一个表中选取数据,然后把数据插入另一个表中. SELECT INTO 语句常用于创建表 ...
- 松软科技课堂:Winform之TextBox
松软科技文(www.sysoft.net.cn): 文本框的几种模式:Multiline(多行).PasswordChar(密码)将文本框的PasswordChar设为*就是密码框效果,将MultiL ...
- 一个基于vue的仪表盘demo
最近写了一个基于vue的仪表盘,其中 主要是和 transform 相关的 css 用的比较多.给大家分享一下,喜欢的话点个赞呗?嘿嘿 截图如下: 实际效果查看地址:https://jhcan333. ...
- linux常见报错
零.目录 一. 文件和目录类 File exist 文件已经存在 No such file or directory 没有这个文件或目录(这个东西不存在) command not found 命令找不 ...
- Spring IOC MVC DI简单实现
目录的大致情况:所有的类都会加进来. 1.首先先写基本的Controller Service ServiceImpl Controller Service ServiceImpl是用来验证下面写的框架 ...
- Java 集合转换(数组、List、Set、Map相互转换)
package com.example.test; import java.util.ArrayList; import java.util.Arrays; import java.util.Hash ...
- 品Spring:能工巧匠们对注解的“加持”
问题的描述与方案的提出 在Spring从XML转向注解时,为了自身的开发方便,对注解含义进行了扩充(具体参考本号上一篇文章). 这个扩充直接导致了一个问题,就是需要从注解往元注解以及元元注解(即沿着从 ...
- FlagCounter被封杀?自己实现一个简单的多国访客计数器
起因 前段时间发现博客右边的FlagCounter计数器突然没了,又看到了博客园封杀了FlagCounter的消息,有点摸不着头脑.于是上FlagCounter的网站上看了一眼,发现最近出现的来自新国 ...
- C++进程间通讯方式
1.剪切板模式. 在MFC里新建两个文本框和两个按钮,点击发送按钮相当于复制文本框1的内容,点击接收按钮相当于粘贴到文本框2内: 发送和接收按钮处功能实现如下: void CClipboard2Dlg ...