刷题总结——二逼平衡树(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小值,查询区间某个值排 ...
随机推荐
- volatile引发的一系列血案
最早读<深入理解java虚拟机>对于volatile部分就没有读明白,最近重新拿来研究并记录一些理解 理解volatile前需要把以下这些概念或内容理解: 1.JMM内存模型 2.并发编程 ...
- Python封装补充
property属性 property实际是setter getter deleter是集合体,并不是一个单独的方法 import math # 使用的库 class Circle: def __in ...
- NOIP2016——一个逗号引发的血案
今年江西省报名人数一下子增起来了 隔壁中学来了80+人(虽然都是来给我们垫底的...临时被老师抓来上战场 总之我们赛区参赛人数总算多起来了(起码没再减50%...连续4年减50%真不是随便说说的... ...
- cephfs 挂载 卸载
#挂载 sudo ceph-fuse -m 10.1.xx.231:6789,10.1.xx.232:6789,10.1.xx.233:6789 -r /MySQL-BK /data/backup # ...
- overtrue/wechat 包 由 sys_get_temp_dir 引发的 the directory "c:\Windows" is not writable
vendor\overtrue\wechat\src\Foundation\Application.php registerBase 方法 在初始化属性时 $this['cache'] = funct ...
- destoon添加修改会员信息时,信息丢失
最近做一destoon项目,因注册字段太多,分了几个步骤.分几个页面来修改公司信息.发现有时候修改时以前保存的字段莫名丢失.. 经查是 因为member.class.php add 和 edit时, ...
- destoon 配置文件config.inc.php参数说明
$CFG['db_host']数据库服务器,可以包括端口号,一般为localhost $CFG['db_user']数据库用户名,一般为root $CFG['db_pass']数据库密码 $CFG[' ...
- Python: simple drawings
import cv2; # OpenCV Python import numbers; import numpy as np; import math; import matplotlib; impo ...
- python2和python3,字典和json
Python2的标准数据类型有: Numbers (数字) String (字符串) List (列表) Tuple (元组) Dictionary (字典) Python3的标准数据类型有: Num ...
- C语言结构体初始化的四种方法(转载)
原文:https://blog.csdn.net/ericbar/article/details/79567108 定义 struct InitMember { int first: double s ...