您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
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]
【思路】
线段树套名次树
名次树上的各个操作和普通平衡树大致一样。
一棵线段树,每一个节点为一棵Treap,各操作如下:
操作1 -- 找出[l,r]内k的rank,得到比k小的数量s,则答案为s+1,在区间内统计比k小的数量即可。
操作2 – 找出[l,r]内rank为k的数,二分查找该数M,通过操作1可以得到数M的rank,根据k与rank调整区间。
操作3 – 修改pos上的数为k,在线段树上递归到位置pos,修改路径上的每一棵Treap,对应一次remove与一次insert。
操作4 – 找出[l,r]内k的前驱,在区间每一棵包含区间的Treap上进行Treap中查找前驱的操作,更新ans。
操作5 – 同理4
【代码】
1 #include<cstdio> 2 #include<ctime> 3 #include<cstring> 4 #include<cstdlib> 5 #include<iostream> 6 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 7 using namespace std; 8 9 const int N = 5*1e5+10; 10 const int INF = 1e8; 11 12 int n,m,val[N],tmp; 13 //RANK TREE 14 struct Node { 15 Node* ch[2]; 16 int v,r,s,w; 17 Node(int x):v(x) {ch[0]=ch[1]=NULL; s=w=1; r=rand();} 18 void maintain() { 19 s=w; 20 if(ch[0]!=NULL) s+=ch[0]->s; 21 if(ch[1]!=NULL) s+=ch[1]->s; 22 } 23 int cmp(int x) { 24 if(x==v) return -1; else return x<v? 0:1; 25 } 26 }; 27 void rotate(Node* &o,int d) { 28 Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d],k->ch[d]=o; 29 o->maintain(),k->maintain(); o=k; 30 } 31 void insert(Node* &o,int x) { 32 if(o==NULL) o=new Node(x); 33 else { 34 int d=o->cmp(x); 35 if(d==-1) { o->w++; o->maintain(); return; } 36 insert(o->ch[d],x); 37 if(o->ch[d]->r > o->r) rotate(o,d^1); 38 } 39 o->maintain(); 40 } 41 void remove(Node* &o,int x) { 42 if(o==NULL) return; 43 int d=o->cmp(x); 44 if(d==-1) { 45 Node* u=o; 46 if(o->w>1) { o->w--;o->maintain();return; } 47 if(o->ch[0]!=NULL&&o->ch[1]!=NULL) { 48 int d2=o->ch[0]->r>o->ch[1]->r? 1:0; 49 rotate(o,d2),remove(o->ch[d2],x); 50 } 51 else { 52 if(o->ch[0]!=NULL) o=o->ch[0]; else o=o->ch[1]; 53 delete u; 54 } 55 } else remove(o->ch[d],x); 56 if(o!=NULL) o->maintain(); 57 } 58 void rank(Node* o,int x) { 59 if(o==NULL) return ; 60 int d=o->cmp(x),s=o->ch[0]==NULL? 0:o->ch[0]->s; 61 if(d==-1) { tmp+=s; return ; } 62 else if(d==0) rank(o->ch[0],x); 63 else { tmp+=s+o->w; rank(o->ch[1],x); } 64 } 65 void before(Node* o,int x) { 66 if(o==NULL) return ; 67 if(o->v<x) { tmp=max(tmp,o->v); before(o->ch[1],x); } 68 else before(o->ch[0],x); 69 } 70 void after(Node* o,int x) { 71 if(o==NULL) return ; 72 if(o->v>x) { tmp=min(tmp,o->v); after(o->ch[0],x); } 73 else after(o->ch[1],x); 74 } 75 //SEGMENT TREE 2D 76 Node* root[N>>1]; 77 void build(int u,int L,int R,int r,int x) { 78 insert(root[u],x); 79 if(L==R) return ; 80 int M=(L+R)>>1; 81 if(r<=M) build(u<<1,L,M,r,x); 82 else build(u<<1|1,M+1,R,r,x); 83 } 84 void getrank(int u,int L,int R,int l,int r,int x) { 85 if(l==L && r==R) { rank(root[u],x); return ; } 86 int M=(L+R)>>1; 87 if(r<=M) getrank(u<<1,L,M,l,r,x); 88 else if(M<l) getrank(u<<1|1,M+1,R,l,r,x); 89 else { 90 getrank(u<<1,L,M,l,M,x); 91 getrank(u<<1|1,M+1,R,M+1,r,x); 92 } 93 } 94 void getindex(int x,int y,int k) { 95 int num,L=0,R=INF,M; 96 while(L<=R) { 97 int M=(L+R)>>1; 98 tmp=1; 99 getrank(1,1,n,x,y,M); 100 if(tmp<=k) L=M+1,num=M; 101 else R=M-1; 102 } 103 printf("%d\n",num); 104 } 105 void change(int u,int L,int R,int r,int x,int y) { 106 remove(root[u],x),insert(root[u],y); 107 if(L==R) return ; 108 int M=(L+R)>>1; 109 if(r<=M) change(u<<1,L,M,r,x,y); 110 else change(u<<1|1,M+1,R,r,x,y); 111 } 112 void getbefore(int u,int L,int R,int l,int r,int x) { 113 if(l==L && R==r) { before(root[u],x);return ;} 114 int M=(L+R)>>1; 115 if(r<=M) getbefore(u<<1,L,M,l,r,x); 116 else if(l>M) getbefore(u<<1|1,M+1,R,l,r,x); 117 else { 118 getbefore(u<<1,L,M,l,M,x); 119 getbefore(u<<1|1,M+1,R,M+1,r,x); 120 } 121 } 122 void getafter(int u,int L,int R,int l,int r,int x) { 123 if(l==L && R==r) { after(root[u],x); return ;} 124 int M=(L+R)>>1; 125 if(r<=M) getafter(u<<1,L,M,l,r,x); 126 else if(l>M) getafter(u<<1|1,M+1,R,l,r,x); 127 else { 128 getafter(u<<1,L,M,l,M,x); 129 getafter(u<<1|1,M+1,R,M+1,r,x); 130 } 131 } 132 void read(int& x) { 133 char c=getchar(); int f=1; x=0; 134 while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();} 135 while(isdigit(c)) x=x*10+c-'0',c=getchar(); 136 x*=f; 137 } 138 void trav(Node* o) { 139 if(o==NULL) return ; 140 FOR(i,1,o->w) cout<<o->v<<" "; 141 trav(o->ch[0]),trav(o->ch[1]); 142 } 143 int main() { 144 //freopen("in.in","r",stdin); 145 //freopen("out.out","w",stdout); 146 read(n),read(m); 147 FOR(i,1,n) read(val[i]),build(1,1,n,i,val[i]); 148 int op,a,b,c; 149 while(m--) { 150 read(op),read(a),read(b); 151 switch(op) { 152 case 1: 153 read(c); tmp=1; getrank(1,1,n,a,b,c); 154 printf("%d\n",tmp); 155 break; 156 case 2: 157 read(c); getindex(a,b,c); 158 break; 159 case 3: 160 change(1,1,n,a,val[a],b); val[a]=b; 161 break; 162 case 4: 163 read(c); tmp=0; getbefore(1,1,n,a,b,c); 164 printf("%d\n",tmp); 165 break; 166 case 5: 167 read(c); tmp=INF; getafter(1,1,n,a,b,c); 168 printf("%d\n",tmp); 169 break; 170 } 171 } 172 return 0; 173 }