BZOJ_3196_二逼平衡树_(树套树,线段树+Treap)
描述
http://www.lydsy.com/JudgeOnline/problem.php?id=3196
可以处理区间问题的平衡树.
3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 2412 Solved: 986
[Submit][Status][Discuss]
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]
Source
分析
树套树.可以用线段树套Treap.人生第一道树套树的题...
op1:如果在整区间,直接在该区间的treap上求解.否则分两个区间求解,然后相加.最后+1.
op2:这个不太好直接做,可以二分,每次假定一个值,用这个值去做op1,以此求得一个rank=k+1的数,求rank=k的数等价与求这个数的前驱pre.
op3:先删后加.
op4&op5:如果在整区间,直接在该区间的treap上求解,否则分量个区间求解,pre取最大值,suc取最小值.注意有些数在有些区间可能找不到前驱/后驱,这时pre返回-INF,suc取INF.
p.s.
1.神一样的调了一下午....上午做完普通平衡树感觉自己好不熟练啊居然搞了一上午,中午敲完这个题以为能A,结果RE,之后就没救了...发现时remove函数的问题,也没找到问题在哪,在开始怀疑人生之前换回了白书上的写法,果然A了,再看看原来的写法也没什么错啊.于是重新写了一遍原来的方法,结果A了.然后开始找不同,后来发现是结构体里定义的小于号不知咋地不好使了...C++学得太渣,最后只好舍弃,改为手动判断大小了...也不知道问题出在哪,最后还是没有解决,好遗憾...
1.白书上的remove写法
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std; const int maxn=+,oo=~0u>>;
int n,q;
int a[maxn];
struct Treap{
struct node{
node* ch[];
int v,r,s,c;
node(int v,node* t):v(v){ ch[]=ch[]=t; r=rand(); s=c=; }
bool operator < (const node &rhs) const{ return r<rhs.r; }
void push_up() { s=ch[]->s+ch[]->s+c; }
}*root,*null;
Treap(){
null=new node(,NULL);
null->c=null->s=; null->r=oo;
root=null;
}
void rotate(node* &o,bool d){
node* k=o->ch[!d]; o->ch[!d]=k->ch[d]; k->ch[d]=o;
o->push_up(); k->push_up(); o=k;
}
void insert(node* &o,int x){
if(o==null) o=new node(x,null);
else{
if(x==o->v){ o->s++; o->c++; }
else{
bool d=x>o->v;
insert(o->ch[d],x);
if(o->ch[d]<o) rotate(o,!d);
o->push_up();
}
}
}
void remove(node* &o,int x){
if(o->v==x){
if(o->c>) { o->c--; o->s--; }
else{
if(o->ch[]!=null&&o->ch[]!=null){
bool d=o->ch[]<o->ch[];
rotate(o,d); remove(o->ch[d],x); o->push_up();
}
else{
node* u=o;
if(o->ch[]==null) o=o->ch[]; else o=o->ch[];
delete u;
}
}
}
else{
bool d=x>o->v;
remove(o->ch[d],x);
o->push_up();
}
}
int rank(int x){
int ret=,s;
for(node *t=root;t!=null;){
s=t->ch[]->s+t->c;
if(x>t->v) ret+=s,t=t->ch[];
else t=t->ch[];
}
return ret;
}
int pre(int x){
int ret=-oo;
for(node* t=root;t!=null;){
if(t->v<x) ret=t->v,t=t->ch[];
else t=t->ch[];
}
return ret;
}
int suc(int x){
int ret=oo;
for(node* t=root;t!=null;){
if(t->v>x) ret=t->v,t=t->ch[];
else t=t->ch[];
}
return ret;
}
}; struct Segment_Tree{
Treap tree[maxn*];
void build_tree(int l,int r,int k){
for(int i=l;i<=r;i++) tree[k].insert(tree[k].root,a[i]);
if(l==r) return;
int mid=l+((r-l)>>);
build_tree(l,mid,k<<); build_tree(mid+,r,k<<|);
}
int get_rank(int l,int r,int k,int x,int y,int X){
if(l==x&&r==y) return tree[k].rank(X);
int mid=l+((r-l)>>);
if(y<=mid) return get_rank(l,mid,k<<,x,y,X);
else if(x>mid) return get_rank(mid+,r,k<<|,x,y,X);
else return get_rank(l,mid,k<<,x,mid,X)+get_rank(mid+,r,k<<|,mid+,y,X);
}
void change(int l,int r,int k,int id,int x){
tree[k].remove(tree[k].root,a[id]);
tree[k].insert(tree[k].root,x);
if(l==r) return;
int mid=l+((r-l)>>);
if(id<=mid) change(l,mid,k<<,id,x);
else change(mid+,r,k<<|,id,x);
}
int get_pre(int l,int r,int k,int x,int y,int X){
if(l==x&&r==y) return tree[k].pre(X);
int mid=l+((r-l)>>);
if(y<=mid) return get_pre(l,mid,k<<,x,y,X);
else if(x>mid) return get_pre(mid+,r,k<<|,x,y,X);
else return max(get_pre(l,mid,k<<,x,mid,X),get_pre(mid+,r,k<<|,mid+,y,X));
}
int get_suc(int l,int r,int k,int x,int y,int X){
if(l==x&&r==y) return tree[k].suc(X);
int mid=l+((r-l)>>);
if(y<=mid) return get_suc(l,mid,k<<,x,y,X);
else if(x>mid) return get_suc(mid+,r,k<<|,x,y,X);
else return min(get_suc(l,mid,k<<,x,mid,X),get_suc(mid+,r,k<<|,mid+,y,X));
}
int get_kth(int x,int y,int k){
int l=,r=oo;
while(l<r){
int mid=l+((r-l)>>);
int tmp=get_rank(,n,,x,y,mid)+;
if(tmp<=k) l=mid+;
else r=mid;
}
return get_pre(,n,,x,y,l);
}
}T; int main()
{
scanf("%d%d",&n,&q);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
T.build_tree(,n,);
int qry,l,r,k,x,pos;
for(int i=;i<=q;i++){
scanf("%d",&qry);
switch(qry){
case :
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",T.get_rank(,n,,l,r,x)+);break;
case :
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",T.get_kth(l,r,k));break;
case :
scanf("%d%d",&pos,&x);
T.change(,n,,pos,x);
a[pos]=x;break;
case :
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",T.get_pre(,n,,l,r,x));break;
case :
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",T.get_suc(,n,,l,r,x));break;
}
}
return ;
}
2.另一种remove写法
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std; const int maxn=+,oo=~0u>>;
int n,q;
int a[maxn];
struct Treap{
struct node{
node* ch[];
int v,r,s,c;
node(int v,node* t):v(v){ ch[]=ch[]=t; r=rand(); s=c=; }
void push_up() { s=ch[]->s+ch[]->s+c; }
}*root,*null;
Treap(){
null=new node(,NULL);
null->c=null->s=; null->r=oo;
root=null;
}
void rotate(node* &o,bool d){
node* k=o->ch[!d]; o->ch[!d]=k->ch[d]; k->ch[d]=o;
o->push_up(); k->push_up();
if(o==root) root=k;
o=k;
}
void insert(node* &o,int x){
if(o==null) o=new node(x,null);
else{
if(x==o->v) o->s++, o->c++;
else{
bool d=x>o->v;
insert(o->ch[d],x);
if(o->ch[d]<o) rotate(o,!d);
o->push_up();
}
}
}
void remove(node* &o,int x) {
if(x==o->v) {
if(o->c>) o->c--,o->s--;
else{
bool d=o->ch[]->r<o->ch[]->r;
if(o->ch[d]==null){
delete o;
o=null;
}
else{
rotate(o,!d);
remove(o->ch[!d],x);
o->push_up();
}
}
}
else{
bool d=x>o->v;
remove(o->ch[d],x);
o->push_up();
}
}
int rank(int x){
int ret=,s;
for(node *t=root;t!=null;){
s=t->ch[]->s+t->c;
if(x>t->v) ret+=s,t=t->ch[];
else t=t->ch[];
}
return ret;
}
int pre(int x){
int ret=-oo;
for(node* t=root;t!=null;){
if(t->v<x) ret=t->v,t=t->ch[];
else t=t->ch[];
}
return ret;
}
int suc(int x){
int ret=oo;
for(node* t=root;t!=null;){
if(t->v>x) ret=t->v,t=t->ch[];
else t=t->ch[];
}
return ret;
}
}; struct Segment_Tree{
Treap tree[maxn<<];
void build_tree(int l,int r,int k){
for(int i=l;i<=r;i++) tree[k].insert(tree[k].root,a[i]);
if(l==r) return;
int mid=l+((r-l)>>);
build_tree(l,mid,k<<); build_tree(mid+,r,k<<|);
}
int get_rank(int l,int r,int k,int x,int y,int X){
if(l==x&&r==y) return tree[k].rank(X);
int mid=l+((r-l)>>);
if(y<=mid) return get_rank(l,mid,k<<,x,y,X);
else if(x>mid) return get_rank(mid+,r,k<<|,x,y,X);
else return get_rank(l,mid,k<<,x,mid,X)+get_rank(mid+,r,k<<|,mid+,y,X);
}
void change(int l,int r,int k,int id,int x){
tree[k].remove(tree[k].root,a[id]);
tree[k].insert(tree[k].root,x);
if(l==r) return;
int mid=l+((r-l)>>);
if(id<=mid) change(l,mid,k<<,id,x);
else change(mid+,r,k<<|,id,x);
}
int get_pre(int l,int r,int k,int x,int y,int X){
if(l==x&&r==y) return tree[k].pre(X);
int mid=l+((r-l)>>);
if(y<=mid) return get_pre(l,mid,k<<,x,y,X);
else if(x>mid) return get_pre(mid+,r,k<<|,x,y,X);
else return max(get_pre(l,mid,k<<,x,mid,X),get_pre(mid+,r,k<<|,mid+,y,X));
}
int get_suc(int l,int r,int k,int x,int y,int X){
if(l==x&&r==y) return tree[k].suc(X);
int mid=l+((r-l)>>);
if(y<=mid) return get_suc(l,mid,k<<,x,y,X);
else if(x>mid) return get_suc(mid+,r,k<<|,x,y,X);
else return min(get_suc(l,mid,k<<,x,mid,X),get_suc(mid+,r,k<<|,mid+,y,X));
}
int get_kth(int x,int y,int k){
int l=,r=oo;
while(l<r){
int mid=l+((r-l)>>);
int tmp=get_rank(,n,,x,y,mid)+;
if(tmp<=k) l=mid+;
else r=mid;
}
return get_pre(,n,,x,y,l);
}
}T; int main()
{
scanf("%d%d",&n,&q);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
T.build_tree(,n,);
int qry,l,r,k,x,pos;
for(int i=;i<=q;i++){
scanf("%d",&qry);
switch(qry){
case :
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",T.get_rank(,n,,l,r,x)+);break;
case :
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",T.get_kth(l,r,k));break;
case :
scanf("%d%d",&pos,&x);
T.change(,n,,pos,x);
a[pos]=x;break;
case :
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",T.get_pre(,n,,l,r,x));break;
case :
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",T.get_suc(,n,,l,r,x));break;
}
}
return ;
}
BZOJ_3196_二逼平衡树_(树套树,线段树+Treap)的更多相关文章
- BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树
BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排 ...
- [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树
二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
- 【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数 ...
- 【BZOJ】3196: Tyvj 1730 二逼平衡树(区间第k小+树套树)
http://www.lydsy.com/JudgeOnline/problem.php?id=3196 Treap+树状数组 1WA1A,好伤心,本来是可以直接1A的,这次开始我并没有看题解,就写出 ...
- 洛谷P3332 [ZJOI2013]K大数查询 权值线段树套区间线段树_标记永久化
Code: #include <cstdio> #include <algorithm> #include <string> #include <cstrin ...
- 【BZOJ-3196】二逼平衡树 线段树 + Splay (线段树套平衡树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2271 Solved: 935[Submit][Stat ...
- 【题解】二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730]
[题解]二逼平衡树 [P3380] [BZOJ3196] [Tyvj1730] 传送门:[模板]二逼平衡树(树套树)\([P3380]\) \([BZOJ3196]\) \([TYVJ1730]\) ...
- 「luogu3380」【模板】二逼平衡树(树套树)
「luogu3380」[模板]二逼平衡树(树套树) 传送门 我写的树套树--线段树套平衡树. 线段树上的每一个节点都是一棵 \(\text{FHQ Treap}\) ,然后我们就可以根据平衡树的基本操 ...
随机推荐
- 用Android-X86和VirtualBox打造高性能Android开发环境
不知道有多少Android开发着对Android虚拟机的那悲剧的性能有意见,反正我的看法是:那速度实在是太坑爹了! 为什么Android虚拟机比iOS和WP7的虚拟机要慢很多呢?原因如下: 1. An ...
- 如何关闭SELinux
一般安装linux课程时都把SELinux与iptables安排在后面,使初学者配置linux服务器时不成功,却没有头绪,那是因为在RedHat linux操作系统中默认开启了防火墙,SELinux也 ...
- mac最常用终端命令
1分钟,快速复习下: pwd (显示当前所在路径) ls -l (列出文件的详细信息,如创建者,创建时间,文件的读写权限列表等等) touch `filename`(创建文件) open `file ...
- struts2基于Convention插件的约定映射使用
一.首先说明一点:所谓的基于Convention插件的约定优于配置的使用,并不是严格意义上的零配置,struts.xml文件并不能完全舍弃. 获得Convention插件功能,所必需的jar包有:|a ...
- Java学习笔记(基本数据类型和变量命名规则)
java基本数据类型 变量 1.变量就是可变的量. 2.常量就是不可变的量. 3.字面量:Java的变量和常量中存放的具体的数据成为字面量. 变量 命名规则: (1)首字母是英文字母.$或下划线,由字 ...
- 九度OJ 1042 Coincidence -- 动态规划(最长公共子序列)
题目地址:http://ac.jobdu.com/problem.php?pid=1042 题目描述: Find a longest common subsequence of two strings ...
- 九度OJ 1525 子串逆序打印 -- 2012年Google校园招聘笔试题目
题目地址:http://ac.jobdu.com/problem.php?pid=1525 题目描述: 小明手中有很多字符串卡片,每个字符串中都包含有多个连续的空格,而且这些卡片在印刷的过程中将字符串 ...
- IOS 学习笔记 2015-03-24 OC-API-网络访问-案例一
// // WPSuggest.h // OC-API-网络访问 // // Created by wangtouwang on 15/3/24. // Copyright (c) 2015年 wan ...
- 为什么aspx这么“慢”
首先你要明白什么viewstate:由系统生成的一个隐藏域,用来进行页面状态保持的 里面存放着关于判断页面是否提交的Ispostback,和一些关于服务器控件的状态和数据: (说明下 ,ViewSta ...
- 如何实现.so共享库文件
.so共享库相当于window中的.DLL文件 两个进程同时调用了.so文件,进程就会加载的.so文件到各自的内存空间,而不能实现进程间通讯. .so文件编译的方法: -so文件不需要main文件,即 ...