LG3380 3380 【模板】二逼平衡树(树套树)
题意
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
查询k在区间内的排名
查询区间内排名为k的值
修改某一位值上的数值
查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)
注意上面两条要求和tyvj或者bzoj不一样,请注意
说明
时空限制:2s,128M
\(n,m \leq 5\cdot {10}^4\)
保证有序序列所有值在任何时刻满足$ [0, {10} ^8]$
分析
模板题。
树状数组套权值线段树,时空复杂度\(O((n+m) \log_2^2n)\)
代码
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
#define lowbit(x) (x&-x)
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll;
using std::vector;
vector<int> vs;
co int N=5e4+1,LG=120;
int c[N],n,m;
struct quiz{
int opt,l,r,k;
}q[N];
// Tree Tao Tree
namespace T{
// Interval Tree
int L[N*LG],R[N*LG],sum[N*LG];
int tot,root[N];
int rank(vector<int>&x,int l,int r,int p){
if(l==r) return 1;
int m=(l+r)/2;
if(p<=m){
for(int i=0;i<x.size();++i)
x[i]=x[i]<0?-L[-x[i]]:L[x[i]];
return rank(x,l,m,p);
}
else{
int s=0;
for(int i=0;i<x.size();++i){
x[i]<0?s-=sum[L[-x[i]]]:s+=sum[L[x[i]]];
x[i]=x[i]<0?-R[-x[i]]:R[x[i]];
}
return s+rank(x,m+1,r,p);
}
}
int kth(vector<int>&x,int l,int r,int k){
if(l==r) return l;
int s=0;
for(int i=0;i<x.size();++i)
x[i]<0?s-=sum[L[-x[i]]]:s+=sum[L[x[i]]];
int m=(l+r)/2;
if(s>=k){
for(int i=0;i<x.size();++i)
x[i]=x[i]<0?-L[-x[i]]:L[x[i]];
return kth(x,l,m,k);
}
else{
for(int i=0;i<x.size();++i)
x[i]=x[i]<0?-R[-x[i]]:R[x[i]];
return kth(x,m+1,r,k-s);
}
}
void change(int&x,int l,int r,int p,int d){
if(!x) x=++tot;
sum[x]+=d;
if(l==r) return;
int m=(l+r)/2;
if(p<=m) change(L[x],l,m,p,d);
else change(R[x],m+1,r,p,d);
}
int precessor(vector<int>&x,int l,int r,int p){
if(p==1) return -1;
vector<int>y;
int k=rank(y=x,l,r,p);
if(k==1) return -1;
return kth(y=x,l,r,k-1);
}
int successor(vector<int>&x,int l,int r,int p){
if(p==vs.size()) return -1;
vector<int>y;
int k=rank(y=x,l,r,p+1)-1,s=0; // edit 1: reuse rank
for(int i=0;i<x.size();++i)
x[i]<0?s-=sum[-x[i]]:s+=sum[x[i]];
if(k==s) return -1;
return kth(y=x,l,r,k+1);
}
// Binaru Index Tree
int rank(int l,int r,int v){
vector<int> roots;
for(int i=r;i;i-=lowbit(i))
roots.push_back(root[i]);
for(int i=l-1;i;i-=lowbit(i))
roots.push_back(-root[i]);
return rank(roots,1,vs.size(),v);
}
int kth(int l,int r,int k){
vector<int> roots;
for(int i=r;i;i-=lowbit(i))
roots.push_back(root[i]);
for(int i=l-1;i;i-=lowbit(i))
roots.push_back(-root[i]);
return kth(roots,1,vs.size(),k);
}
void change(int p,int v){
for(int i=p;i<=n;i+=lowbit(i)){
change(root[i],1,vs.size(),c[p],-1); // edit 1:c[p]
change(root[i],1,vs.size(),v,1);
}
c[p]=v;
}
int precessor(int l,int r,int v){
vector<int> roots;
for(int i=r;i;i-=lowbit(i))
roots.push_back(root[i]);
for(int i=l-1;i;i-=lowbit(i))
roots.push_back(-root[i]);
return precessor(roots,1,vs.size(),v);
}
int successor(int l,int r,int v){
vector<int> roots;
for(int i=r;i;i-=lowbit(i))
roots.push_back(root[i]);
for(int i=l-1;i;i-=lowbit(i))
roots.push_back(-root[i]);
return successor(roots,1,vs.size(),v);
}
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n),read(m);
for(int i=1;i<=n;++i)
vs.push_back(read(c[i]));
for(int i=1;i<=m;++i){
read(q[i].opt);
if(q[i].opt!=3){
read(q[i].l),read(q[i].r),read(q[i].k);
if(q[i].opt!=2) vs.push_back(q[i].k);
}
else read(q[i].l),vs.push_back(read(q[i].k));
}
sort(vs.begin(),vs.end()),vs.erase(unique(vs.begin(),vs.end()),vs.end());
for(int i=1;i<=n;++i){
c[i]=lower_bound(vs.begin(),vs.end(),c[i])-vs.begin()+1;
for(int j=i;j<=n;j+=lowbit(j)) // insert
T::change(T::root[j],1,vs.size(),c[i],1);
}
for(int i=1;i<=m;++i){
if(q[i].opt!=2) q[i].k=lower_bound(vs.begin(),vs.end(),q[i].k)-vs.begin()+1; // edit 2: only operator 3
if(q[i].opt==1) printf("%d\n",T::rank(q[i].l,q[i].r,q[i].k));
else if(q[i].opt==2) printf("%d\n",vs[T::kth(q[i].l,q[i].r,q[i].k)-1]);
else if(q[i].opt==3) T::change(q[i].l,q[i].k);
else if(q[i].opt==4){
int re=T::precessor(q[i].l,q[i].r,q[i].k);
if(re==-1) puts("-2147483647");
else printf("%d\n",vs[re-1]);
}
else if(q[i].opt==5){
int re=T::successor(q[i].l,q[i].r,q[i].k);
if(re==-1) puts("2147483647");
else printf("%d\n",vs[re-1]);
}
}
return 0;
}
LG3380 3380 【模板】二逼平衡树(树套树)的更多相关文章
- 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 & 洛谷3380:二逼平衡树——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3196 https://www.luogu.org/problemnew/show/P3380 (题 ...
- 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( ...
- ZJOI2013 K大数查询 和 LG3380【模板】二逼平衡树(树套树)
K大数查询 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c:如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的 ...
- 【BZOJ 3196】二逼平衡树 线段树套splay 模板题
我写的是线段树套splay,网上很多人写的都是套treap,然而本蒟蒻并不会treap 奉上sth神犇的模板: //bzoj3196 二逼平衡树,支持修改某个点的值,查询区间第k小值,查询区间某个值排 ...
随机推荐
- phoenix部署手册-基于hbase
背景描述: phoenix基于hbase的SQL层,映射hbase的表,也可以映射视图(VIEW) 部署安装比较简单 映射表和视图的区别: 映射表: 在Phoenix建表错误不易更改: 删除会连同hb ...
- 20145219 《Java程序设计》第02周学习总结
20145219 <Java程序设计>第02周学习总结 教材学习内容总结 类型:基本类型.类类型(参考类型) 基本类型: 整数:short占2字节,int占4字节,long占8字节 字节: ...
- 安装专业版的linux的方法 图解安装专业版的linux
按装一个linux系统其实很简单,不再像以前那样光光盘就好些个,一不小心还又可能装错,实在也是一个大问题.现在好了基本上都是简单安装+网络升级先安装主要的后面如果需要什么在装什么?大大简化了流程.不行 ...
- NumPy字节交换
NumPy - 字节交换 我们已经知道,存储在计算机内存中的数据取决于 CPU 使用的架构. 它可以是小端(最小有效位存储在最小地址中)或大端(最小有效字节存储在最大地址中). numpy.ndarr ...
- Mine_hibernate
1. __z知识点\整理_归纳 ==> "ZC_归纳.txt" 和 "ZC_归纳__12_用Eclipse开发hibernate.txt" 2.
- 初探UiAutomator2.0中使用Xpath定位元素
J 今天的主题是讲一下在使用过程中遇到的一个问题,如何在UiAutomator2.0中使用Xpath定位元素? 背景 现在的app在打包成apk的时候都是有加固处理的,各种混淆加固,所以已经破坏了或扰 ...
- 论Spark高手是怎样炼成的
SPARK J大数据的处理怎么能变快一点,答案是请用spark,因为它是基于内存的,可以有效减少数据的落地次数.Spark性能超过Hadoop百倍,从多迭代批量处理出发,兼收并蓄数据仓库.流处理和图计 ...
- Redis分区探究
Redis比较好的分区算法是采用Hash分区算法 也就是我们可以将所有的server例如:user1,user2,user3.通过hash函数将key转化为一个数字然后求余找到需要存储的server. ...
- jQuery: Redirect to other URL
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title></title> ...
- Gogs/Gitea 在 docker 中部署
注:Gitea是Gogs的一个分支版本,由多个维护者开发,支持搜索.lfs等,但是BUG较多,稳定性似乎没有Gogs好. #### 安装 ####// Gogs$ docker pull gogs/g ...