刷题总结——二逼平衡树(bzoj3224线段树套splay)
题目:
Description
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
Input
第一行两个数 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的后继
Output
对于操作1,2,4,5各输出一行,表示查询结果
Sample Input
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
Sample Output
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
题解:
哎···这道题充分证明了我的代码能力和专注力是tm有多弱····
调了一个早上的代码···终于发现错哪里了····只是因为update里面的=写成了+=···
第一我打的时候打错了···第二我调的时候竟然没有看到这一点···我勒个大艹···
然后一个上午的时间就荒废在了这一个等号里···
下次打的时候我tm一定要注意细节了···不要以为打得顺手就打得正确···
题解的话···我在找标称对拍的时候惊讶的发现网上的一个小姐姐竟然和我写得几乎一模一样·····这里就引用她的吧(其实我splay的版基本都是看她的···)%%%%%%Clove_unique:
线段树套splay,简单地说就是线段树的每一个节点都吊着一颗splay,表示的是线段树当前节点所表示的区间的点,按权值排序。
Q1:线段树常规查询区间,每一次统计小于k的点的个数再相加。
Q2:这个是最麻烦也是最精妙的一问,解决方法是二分答案,每二分到一个答案查询一下这个答案在这个区间内的排名,如果排名等于k+1的话返回它的pre即可。注意这里二分满 足条件之后不用查询pre,答案直接为head-1,可以证明head-1一定在序列中。
Q3:相当于线段树的点修改,在splay中删除再插入即可。
Q4:线段树常规查询区间,每一次找区间内比k小的最大的数,然后取max
Q5:类似于Q4,每一次找区间内比k大的最小的数,然后取min
自己再解释一下Q2的操作吧···询问的是排名为k的数···我们先找出第一个大于至少k的数最小的数x··如果是等于,那么此时left-1肯定是答案(最后right会等于left),如果是大于多于 k个数量的数··那么 想当于是x大于x-1,而x-1又大于少于k个数量的数···这种情况下x-1肯定是有重复的个数的,在连续的x-1中的某一x-1肯定刚好大于等于k个数量的数···那么x-1,即 left-1就是答案····如果x是大于等于k个数量的数,显然x-1是答案
当然这道题套treap会快太多···然而我并不想转treap···指针写起来太麻烦····
另外这道题如果怕爆空间可以回收节点·····然而我懒得写了···
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=4e6+;
int root[N],son[N][],father[N],key[N],size[N],tot,n,m,num[],maxx=,cnt[N];
const int inf=1e9;
inline int R()
{
char c;int f=,i=;
for(c=getchar();(c<''||c>'')&&c!='-';c=getchar());
if(c=='-') c=getchar(),i=-;
for(;c<=''&&c>='';c=getchar())
f=(f<<)+(f<<)+c-'';
return f*i;
}
inline void clear(int now)
{
if(!now) return;
cnt[now]=son[now][]=son[now][]=father[now]=size[now]=;key[N]=;
}
inline void update(int now)
{
if(!now) return;
size[now]=cnt[now]+(son[now][]?size[son[now][]]:)+(son[now][]?size[son[now][]]:);
}
inline int get(int now){return son[father[now]][]==now;}
inline void rotate(int now)
{
int fa=father[now],ofa=father[fa],which=get(now);
son[fa][which]=son[now][which^],father[son[fa][which]]=fa;
son[now][which^]=fa,father[fa]=now,father[now]=ofa;
if(ofa) son[ofa][son[ofa][]==fa]=now;
update(fa),update(now);
}
inline void splay(int k,int now)
{
while(father[now])
{
if(father[father[now]])
rotate(get(now)==get(father[now])?father[now]:now);
rotate(now);
}
root[k]=now;
}
inline int findkth(int k,int v) //查询排名
{
int now=root[k],ans=;
while(true)
{
if(!now) return ans;
if(v==key[now]) return (son[now][]?size[son[now][]]:)+ans;
else if(v>key[now])
{
ans+=(son[now][]?size[son[now][]]:)+cnt[now];
now=son[now][];
}
else if(v<key[now]) now=son[now][];
}
}
inline int findpos(int k,int v) //找到位置
{
int now=root[k];
while(true)
{
if(v==key[now]) return now;
else if(v<key[now]) now=son[now][];
else now=son[now][];
}
}
inline void insert(int k,int v)
{
int now=root[k],last=;
while(true)
{
if(!now)
{
now=++tot;father[now]=last;key[now]=v;size[now]=cnt[now]=;son[now][]=son[now][]=;
if(!root[k]) root[k]=now;
else
{
son[last][v>key[last]]=now;
update(last);
splay(k,now);
}
break;
}
else if(v==key[now])
{
cnt[now]++;update(now);update(last);
splay(k,now);
break;
}
last=now;now=son[now][v>key[now]];
}
}
inline int pre(int k)
{
int now=son[root[k]][];
while(son[now][]) now=son[now][];
return now;
}
inline void del(int k,int v)
{
int now=findpos(k,v);
splay(k,now);
if(cnt[root[k]]>) {cnt[root[k]]--,update(root[k]);return;}
else if(!son[root[k]][]&&!son[root[k]][]){clear(root[k]);root[k]=;return;}
else if(!son[root[k]][])
{
int oldroot=root[k];root[k]=son[root[k]][];father[root[k]]=;
clear(oldroot);return;
}
else if(!son[root[k]][])
{
int oldroot=root[k];root[k]=son[root[k]][];father[root[k]]=;
clear(oldroot);return;
}
else
{
int oldroot=root[k];
int leftbig=pre(k);splay(k,leftbig);
son[root[k]][]=son[oldroot][];
father[son[root[k]][]]=root[k];
update(root[k]);clear(oldroot);return;
}
}
inline int findpre(int k,int v)
{
int now=root[k],ans=;
while(now)
{
if(key[now]<v)
{
if(ans<key[now]) ans=key[now];
now=son[now][];
}
else now=son[now][];
}
return ans;
}
inline int findnxt(int k,int v)
{
int now=root[k],ans=inf;
while(now)
{
if(key[now]>v)
{
if(ans>key[now]) ans=key[now];
now=son[now][];
}
else now=son[now][];
}
return ans;
}
//---------------------------------------------splay
inline void seginsert(int k,int l,int r,int x,int v)
{
insert(k,v);
if(l==r) return;
int mid=(l+r)/;
if(x<=mid) seginsert(k*,l,mid,x,v);
else seginsert(k*+,mid+,r,x,v);
return;
}
inline int segfindkth(int k,int l,int r,int x,int y,int v)
{
if(l>=x&&r<=y) return findkth(k,v);
int mid=(l+r)/;int temp=;
if(x<=mid) temp+=segfindkth(k*,l,mid,x,y,v);
if(y>mid) temp+=segfindkth(k*+,mid+,r,x,y,v);
return temp;
}
inline void segmodify(int k,int l,int r,int x,int v)
{
del(k,num[x]);
insert(k,v);
if(l==r) return;
int mid=(l+r)/;
if(x<=mid) segmodify(k*,l,mid,x,v);
else segmodify(k*+,mid+,r,x,v);
}
inline int segpre(int k,int l,int r,int x,int y,int v)
{
if(l>=x&&r<=y) return findpre(k,v);
int mid=(l+r)/;int temp=;
if(x<=mid) temp=max(temp,segpre(k*,l,mid,x,y,v));
if(y>mid) temp=max(temp,segpre(k*+,mid+,r,x,y,v));
return temp;
}
inline int segnxt(int k,int l,int r,int x,int y,int v)
{
if(l>=x&&r<=y) return findnxt(k,v);
int mid=(l+r)/;int temp=inf;
if(x<=mid) temp=min(temp,segnxt(k*,l,mid,x,y,v));
if(y>mid) temp=min(temp,segnxt(k*+,mid+,r,x,y,v));
return temp;
}
inline void dfs(int now)
{
cout<<key[now]<<" ";
if(son[now][]) dfs(son[now][]);
if(son[now][]) dfs(son[now][]);
}
int main()
{
n=R(),m=R();int op,a,b,c;
for(int i=;i<=n;i++) a=R(),seginsert(,,n,i,a),num[i]=a,maxx=max(maxx,num[i]);
while(m--)
{
op=R();
if(op==) {a=R(),b=R(),c=R();printf("%d\n",segfindkth(,,n,a,b,c)+);}
else if(op==)
{
a=R(),b=R(),c=R();
int le=,ri=maxx+;int ans=;
while(le!=ri)
{
int mid=(le+ri)/;
int temp=segfindkth(,,n,a,b,mid);
if(temp<c) le=mid+;
else ri=mid;
}
printf("%d\n",le-);
}
else if(op==) {a=R(),b=R();segmodify(,,n,a,b);num[a]=b;maxx=max(maxx,b);}
else if(op==) {a=R(),b=R(),c=R();printf("%d\n",segpre(,,n,a,b,c));}
else if(op==) {a=R(),b=R(),c=R();printf("%d\n",segnxt(,,n,a,b,c));}
}
return ;
}
刷题总结——二逼平衡树(bzoj3224线段树套splay)的更多相关文章
- BZOJ 3196 Tyvj 1730 二逼平衡树:线段树套splay
传送门 题意 给你一个长度为 $ n $ 有序数列 $ a $ ,进行 $ m $ 次操作,操作有如下几种: 查询 $ k $ 在区间 $ [l,r] $ 内的排名 查询区间 $ [l,r] $ 内排 ...
- bzoj 3196 Tyvj 1730 二逼平衡树【线段树 套 splay】
四舍五入就是个暴力. 对于线段树的每个区间都开一棵按权值排序的splay 对于第二个操作,二分一下,每次查询mid的排名,复杂度 $ O(nlog(n)^{3}) $ 其余的操作都是$ O(nlog( ...
- [BZOJ3196] [Tyvj1730] 二逼平衡树(线段树 套 Splay)
传送门 至少BZOJ过了,其他的直接弃. 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的 ...
- 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 二逼平衡树 【线段树套平衡树】
题目 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱 ...
- BZOJ3196 二逼平衡树 ZKW线段树套vector(滑稽)
我实在是不想再打一遍树状数组套替罪羊树了... 然后在普通平衡树瞎逛的时候找到了以前看过vector题解 于是我想:为啥不把平衡树换成vector呢??? 然后我又去学了一下ZKW线段树 就用ZKW线 ...
- 【bzoj3196-二逼平衡树】线段树套平衡树
http://acm.hust.edu.cn/vjudge/problem/42297 [题目描述] 写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间 ...
- 【BZOJ 3196】二逼平衡树 线段树套splay 模板题
我写的是线段树套splay,网上很多人写的都是套treap,然而本蒟蒻并不会treap 奉上sth神犇的模板: //bzoj3196 二逼平衡树,支持修改某个点的值,查询区间第k小值,查询区间某个值排 ...
随机推荐
- Django 从0开始创建一个项目
title: Django 从0开始创建一个项目 tags: Django --- Django 从0开始创建一个项目 创建Django工程及配置 创建工程:django-admin starproj ...
- Google 出品的 Java 编码规范,强烈推荐,权威又科学!
原文:google.github.io/styleguide/javaguide.html 译者:Hawstein 来源:hawstein.com/2014/01/20/google-java-sty ...
- HTML5<footer>元素
HTML5中<footer>元素是用来描述文档中的底部信息,比如:版本,版权,作者,链接声明,联系信息,时间等等. 实例: <footer> <p>这是一个底部的信 ...
- IDEA搭建Springboot项目时报错jdk的问题
装了jdk并且配置了JAVA_HOME 与path还报错 No Java SDK of appropriate version found. In addition to the IntelliJ P ...
- oracle 将查询结果输出到txt文件里
在查询语句里先输入spool filepath 中间是需要查询的语句,最后spool off 就会把中间查询的结果都输入到file文件里 spool E:\log.txt; select id,nam ...
- 01_9_Struts用ModelDriven接收参数
01_9_Struts用ModelDriven接收参数 1. 配置struts.xml文件 <package name="user" namespace="/use ...
- (转发)IOS高级开发~Runtime(四)
用C代替OC: #import <objc/runtime.h> #import <objc/message.h> #import <stdio.h> extern ...
- 创建自定义 Estimator
ref 本文档介绍了自定义 Estimator.具体而言,本文档介绍了如何创建自定义 Estimator 来模拟预创建的 Estimator DNNClassifier 在解决鸢尾花问题时的行为.要详 ...
- new和delete的动态分配。
c++对象模型 视频的实际操作 note: 1.虚函数有虚指针,所以是4,不管有几个虚函数, 都只有一个vptr来存放调用的虚函数的地址. 2.子类的内存是父类内存的加自己的数据内存. 3.clas ...
- c内置数据类型
参考 C与指针 第三章 类型 类型标识符 字节 表示数值范围 备注 整型 [signed] int 2* -32768~32767 -2^15 ~ (2^15 -1) 无符号整型 unsigned [ ...