您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)
第一行两个数 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的后继
对于操作1,2,4,5各输出一行,表示查询结果
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; }