3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 775 Solved: 316
[Submit][Status]
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
9 6
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
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
2
4
3
4
9
4
3
4
9
HINT
1.n和m的数据范围:n,m<=50000
2.序列中每个数的数据范围:[0,1e8]
3.虽然原题没有,但事实上5操作的k可能为负数
题解:
需要注意几点:
1.一个数的rank是比它小的数的个数+1
2.要使用正确的二分查找
在查找区间第k小的时候,相当于在rank数组中查询k,如果k出现了那么返回k最后出现的位置 否则返回一个位置在这个位置插入k后,rank数组仍然有序
就如上一篇博文中的YES-RIGHT NO-LEFT类型的二分查找
3.求前驱后继的代码要想好怎么写
以pred为例,节点为0时返回-inf,关键值<=节点值则到左子树去寻找,否则到右子树并且判断返回值是否为-inf,
是的话说明右子树为空,而该节点是比关键值小的一个值,没有比它大的了,所以前驱就是该节点
代码:
1 uses math; 2 const maxn=50000+1000;inf=1000000000; 3 type node=record 4 l,r,lch,rch,rt,mid:longint; 5 end; 6 var t:array[0..8*maxn] of node; 7 l,r,s,w,rnd,v,a:array[0..20*maxn] of longint; 8 i,n,m,x,y,z,tot,ch:longint; 9 procedure pushup(k:longint); 10 begin 11 s[k]:=s[l[k]]+s[r[k]]+w[k]; 12 end; 13 procedure rturn(var k:longint); 14 var t:longint; 15 begin 16 t:=l[k];l[k]:=r[t];r[t]:=k;s[t]:=s[k];pushup(k);k:=t; 17 end; 18 procedure lturn(var k:longint); 19 var t:longint; 20 begin 21 t:=r[k];r[k]:=l[t];l[t]:=k;s[t]:=s[k];pushup(k);k:=t; 22 end; 23 procedure ins(var k,num:longint); 24 begin 25 if k=0 then 26 begin 27 inc(tot);k:=tot;v[k]:=num;s[k]:=1;w[k]:=1;l[k]:=0;r[k]:=0; 28 rnd[k]:=random(maxlongint);exit; 29 end; 30 inc(s[k]); 31 if num=v[k] then inc(w[k]) 32 else if num<v[k] then begin ins(l[k],num);if rnd[l[k]]<rnd[k] then rturn(k);end 33 else begin ins(r[k],num);if rnd[r[k]]<rnd[k] then lturn(k);end; 34 end; 35 procedure del(var k,num:longint); 36 begin 37 if v[k]=num then 38 begin 39 if w[k]>1 then begin dec(w[k]);dec(s[k]);exit;end; 40 if l[k]*r[k]=0 then k:=l[k]+r[k] 41 else if rnd[l[k]]<rnd[r[k]] then begin rturn(k);del(k,num);end 42 else begin lturn(k);del(k,num);end; 43 exit; 44 end; 45 dec(s[k]); 46 if num<v[k] then del(l[k],num) else del(r[k],num); 47 end; 48 procedure build(k,x,y:longint); 49 var i:longint; 50 begin 51 with t[k] do 52 begin 53 l:=x;r:=y;mid:=(l+r)>>1; 54 for i:=l to r do ins(rt,a[i]); 55 if l=r then exit; 56 lch:=k<<1;rch:=k<<1+1; 57 build(lch,l,mid);build(rch,mid+1,r); 58 end; 59 end; 60 procedure change(k,x,y:longint); 61 begin 62 with t[k] do 63 begin 64 del(rt,a[x]);ins(rt,y); 65 if l=r then exit; 66 if x<=mid then change(lch,x,y) 67 else change(rch,x,y); 68 end; 69 end; 70 function pred(k,num:longint):longint; 71 begin 72 if k=0 then exit(-inf); 73 if num<=v[k] then pred:=pred(l[k],num) 74 else 75 begin 76 pred:=pred(r[k],num); 77 if pred=-inf then pred:=v[k]; 78 end; 79 end; 80 function succ(k,num:longint):longint; 81 begin 82 if k=0 then exit(inf); 83 if num>=v[k] then succ:=succ(r[k],num) 84 else 85 begin 86 succ:=succ(l[k],num); 87 if succ=inf then succ:=v[k]; 88 end; 89 end; 90 function findpred(k,x,y,z:longint):longint; 91 begin 92 with t[k] do 93 begin 94 if (l=x) and (r=y) then exit(pred(rt,z)); 95 if y<=mid then exit(findpred(lch,x,y,z)) 96 else if x>mid then exit(findpred(rch,x,y,z)) 97 else exit(max(findpred(lch,x,mid,z),findpred(rch,mid+1,y,z))); 98 end; 99 end; 100 function findsucc(k,x,y,z:longint):longint; 101 begin 102 with t[k] do 103 begin 104 if (l=x) and (r=y) then exit(succ(rt,z)); 105 if y<=mid then exit(findsucc(lch,x,y,z)) 106 else if x>mid then exit(findsucc(rch,x,y,z)) 107 else exit(min(findsucc(lch,x,mid,z),findsucc(rch,mid+1,y,z))); 108 end; 109 end; 110 111 function rank(k,num:longint):longint; 112 begin 113 if k=0 then exit(0); 114 if num=v[k] then exit(s[l[k]]) 115 else if num<v[k] then exit(rank(l[k],num)) 116 else exit(s[l[k]]+w[k]+rank(r[k],num)); 117 end; 118 function query(k,x,y,num:longint):longint; 119 begin 120 with t[k] do 121 begin 122 if (l=x) and (r=y) then exit(rank(rt,num)); 123 if y<=mid then exit(query(lch,x,y,num)) 124 else if x>mid then exit(query(rch,x,y,num)) 125 else exit(query(lch,x,mid,num)+query(rch,mid+1,y,num)); 126 end; 127 end; 128 procedure solverank; 129 begin 130 readln(x,y,z); 131 writeln(query(1,x,y,z)+1); 132 end; 133 procedure solvefind; 134 var l,r,mid:longint; 135 begin 136 readln(x,y,z); 137 l:=0;r:=inf; 138 while l<=r do 139 begin 140 mid:=(l+r)>>1; 141 if query(1,x,y,mid)+1>z then r:=mid-1 else l:=mid+1; 142 end; 143 writeln(r); 144 end; 145 procedure solvechange; 146 begin 147 readln(x,y); 148 change(1,x,y); 149 a[x]:=y; 150 end; 151 procedure solvepred; 152 begin 153 readln(x,y,z); 154 writeln(findpred(1,x,y,z)); 155 end; 156 procedure solvesucc; 157 begin 158 readln(x,y,z); 159 writeln(findsucc(1,x,y,z)); 160 end; 161 162 procedure init; 163 begin 164 tot:=0; 165 readln(n,m); 166 for i:=1 to n do read(a[i]);readln; 167 build(1,1,n); 168 end; 169 procedure main; 170 begin 171 for i:=1 to m do 172 begin 173 read(ch); 174 case ch of 175 1:solverank; 176 2:solvefind; 177 3:solvechange; 178 4:solvepred; 179 5:solvesucc; 180 end; 181 end; 182 end; 183 begin 184 assign(input,'input.txt');assign(output,'output.txt'); 185 reset(input);rewrite(output); 186 init; 187 main; 188 close(input);close(output); 189 end.