3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1363 Solved: 579
[ 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]
http://www.lydsy.com/JudgeOnline/problem.php?id=3196
记原数组为a[i] i从1开始。
基本的Treap树这中平衡树结构能够查找某数的rank、先驱、后继、第k大、结点修改,复杂度分别为logn、logn、logn、logn*logn、logn。
加入了区间的思想之后,就用线段树进行统计,每个线段树结点下都挂着一颗Treap树统计该区间中的每个数。
操作1:找k在某段区间的rank,只要用线段树统计每个子区间的情况,该rank等于小于k的数的个数之和,[1,6] = [1,4]+[5,6],把这样精确覆盖的小区间依次求出。
操作2:找出rank为k的数,二分操作1的rank,找rank小于等于k的最大的数。
操作3:修改pos位置的值为k,对于所有包含pos的线段树的结点,都应该修改这个a[pos]为k,那么转换为Treap的操作,只要先统一删除a[pos]这个值,再插入k这个值就好了。
操作4:找区间[l,r]里小于k的最大的数,和操作1类似,Treap树找前驱就是从根开始往下走,边走边统计。
操作5:找区间[l,r]里大于k的最小的数,和操作4类似,比较符号和儿子都倒过来再写一遍。
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
const int N = 50001;
const int inf = 100000000;
struct Node{
Node* ch[2];
int r,v,s,w;//儿子 随机数 值 结点总数 次数
void init(int v=0){
this->v = v;
ch[0] = ch[1] = NULL;
r = rand();
s = 1;
w = 1;
}
bool operator <(const Node& rhs)const{
return r<rhs.r;
}
int cmp(int x)const{
if (x==v) return -1;
return x<v ? 0 : 1;
}
void maintain(){
s = w;
if (ch[0]) s += ch[0]->s;
if (ch[1]) s += ch[1]->s;
}
};
Node* root[N*4]; int a[N];
Node node[N*4*16];
int tot=1;int tmp;
int n, m;
Node* newNode(int v){
node[tot].init(v);
return &node[tot++];
}
void rotate(Node* &o,int d){
Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
o->maintain(); k->maintain(); o = k;
}
void insert(Node* &o,int num){
if (!o)o = newNode(num);
else{
int d = o->cmp(num);
if (d<0){o->w++;}
else{
insert(o->ch[d], num);
if (o->ch[d] > o) rotate(o,d^1);
}
}
o->maintain();
}
void build(int o,int l,int r,int x,int num){
insert(root[o],num);
if(l==r) return;
int m = (l+r)>>1;
if(x<=m) build(o<<1,l,m,x,num);
else build(o<<1|1,m+1,r,x,num);
}
void ask_rank(Node* &o,int num){
if (!o) return;
else if(num == o->v) { if(o->ch[0])tmp+=o->ch[0]->s; return;}
else if(num < o->v) ask_rank(o->ch[0], num);
else{
tmp += o->ch[0]? o->ch[0]->s : 0;
tmp += o->w;
ask_rank(o->ch[1], num);
}
}
void get_rank(int o,int l,int r,int x,int y,int num){
if(l==x && r==y) {
ask_rank(root[o], num); return ;
}
int mid = (l+r)>>1;
if (mid>=y) get_rank(o<<1,l,mid,x,y,num);
else if (mid<x) get_rank(o<<1|1,mid+1,r,x,y,num);
else{
get_rank(o<<1,l,mid,x,mid,num);
get_rank(o<<1|1,mid+1,r,mid+1,y,num);
}
}
void get_index(int x, int y, int k){
int num;
int l = 0, r = inf, m;
while(l<=r){
m = (l+r)>>1;
tmp = 1;
get_rank(1, 1, n, x, y, m);
if (tmp<=k){
l = m+1;
num = m;
}
else{
r = m-1;
}
}
printf("%d\n", num);
}
void del(Node* &o,int num){
int d = o->cmp(num);
if (d<0){
if (o->w==1){
if (o->ch[0] && o->ch[1]){
int d2 = (o->ch[0]) > (o->ch[1]);
rotate(o,d2); del(o->ch[d2], num);
}
else{
if (o->ch[0]){
o = o->ch[0];
}
else if (o->ch[1]){
o = o->ch[1];
}
else{
o = NULL;
}
}
}else{
o->w--;
}
}
else{
del(o->ch[d], num);
}
if(o) o->maintain();
}
void change(int o,int l,int r,int x,int nxt,int cur){
del(root[o],cur);
insert(root[o],nxt);
if(l==r) return;
int m = (l+r)>>1;
if(x<=m) change(o<<1,l,m,x,nxt,cur);
else change(o<<1|1,m+1,r,x,nxt,cur);
}
void ask_before(Node* &o,int num){
if (!o) return;
else if (o->v < num) {
tmp = max(o->v, tmp);
ask_before(o->ch[1], num);
}
else{
ask_before(o->ch[0], num);
}
}
void get_before(int o,int l,int r,int x,int y,int num){
if(l==x && r==y) {
ask_before(root[o], num); return ;
}
int mid = (l+r)>>1;
if (mid>=y) get_before(o<<1,l,mid,x,y,num);
else if (mid<x) get_before(o<<1|1,mid+1,r,x,y,num);
else{
get_before(o<<1,l,mid,x,mid,num);
get_before(o<<1|1,mid+1,r,mid+1,y,num);
}
}
void ask_after(Node* &o,int num){
if (!o) return;
else if (o->v > num) {
tmp = min(o->v, tmp);
ask_after(o->ch[0], num);
}
else{
ask_after(o->ch[1], num);
}
}
void get_after(int o,int l,int r,int x,int y,int num){
if(l==x && r==y) {
ask_after(root[o], num); return ;
}
int mid = (l+r)>>1;
if (mid>=y) get_after(o<<1,l,mid,x,y,num);
else if (mid<x) get_after(o<<1|1,mid+1,r,x,y,num);
else{
get_after(o<<1,l,mid,x,mid,num);
get_after(o<<1|1,mid+1,r,mid+1,y,num);
}
}
int main()
{
int op, l, r, k, pos;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++) build(1,1,n,i,a[i]);
while(m--){
scanf("%d", &op);
if (op == 1){
scanf("%d%d%d", &l, &r, &k);
tmp = 1;
get_rank(1,1,n,l,r,k);
printf("%d\n", tmp);
}
else if (op == 2){
scanf("%d%d%d", &l, &r, &k);
get_index(l,r,k);
}
else if (op == 3){
scanf("%d%d", &pos, &k);
change(1,1,n,pos,k,a[pos]);
a[pos] = k;
}
else if (op == 4){
scanf("%d%d%d", &l, &r, &k);
tmp = 0;
get_before(1,1,n,l,r,k);
printf("%d\n", tmp);
}
else if (op == 5){
scanf("%d%d%d", &l, &r, &k);
tmp = inf;
get_after(1,1,n,l,r,k);
printf("%d\n", tmp);
}
}
return 0;
}