BZOJ3196二逼平衡树树套树
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3196二逼平衡树树套树相关的知识,希望对你有一定的参考价值。
3196: Tyvj 1730 二逼平衡树
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3776 Solved: 1483
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可能为负数
Q and A
Q:这题怎么搞?
A:外层线段树。。。内层平衡树。。。
Q:真哒?我怎么A不了?
A:这,要拼命水。
Q:那。。。怎么水呢?
A:xjb乱水,O3。。。读入优化。。。各种卡常数。。。卡过10s算数。
Q:那么我怎么看见有人2000ms过了呢?
A:因为正解是整体二分啊,那是大佬专用的神级存在,我辈就不要凑热闹了。
1.外层线段树既然使用root数组,就应当开到区间大小的3倍以上!!!
2.BST中找一个节点的前驱、后继、排名,可以从根按照key相对于x的位置一路找下来得到解.
3.读入优化收效甚微但是刚好够我卡过去.
2080186 | The_Unbeatable | 3196 | Accepted | 51704 kb | 9760 ms | C++/Edit | 6430 B | 2017-05-25 19:06:26 |
1 %:pragma GCC optimize(3) 2 #include<cstdio> 3 #include<queue> 4 #include<iostream> 5 using namespace std; 6 const int N=50005; 7 const int M=2100001; 8 const int INF=1e8+5; 9 int n,root[N*5],lch[M],rch[M],size[M],key[M],fa[M],rep[M],S=1,rec[N]; 10 queue<int> Q; 11 inline void Discard(int x) 12 { 13 lch[x]=rch[x]=key[x]=rep[x]=size[x]=fa[x]=0; 14 if(x) Q.push(x); 15 } 16 inline int newnode() 17 { 18 if(!Q.empty()) 19 { 20 int ret=Q.front(); 21 Q.pop(); 22 return ret; 23 } 24 return ++S; 25 } 26 inline void update(int p) {size[p]=rep[p]+size[lch[p]]+size[rch[p]];} 27 inline void zig(int x) 28 { 29 int f=fa[x],gf=fa[f]; 30 fa[f]=x; 31 fa[x]=gf; 32 if(gf) 33 { 34 if(lch[gf]==f) lch[gf]=x; 35 else rch[gf]=x; 36 } 37 lch[f]=rch[x]; 38 if(rch[x]) fa[rch[x]]=f; 39 rch[x]=f; 40 update(f); 41 update(x); 42 } 43 inline void zag(int x) 44 { 45 int f=fa[x],gf=fa[f]; 46 fa[f]=x; 47 fa[x]=gf; 48 if(gf) 49 { 50 if(lch[gf]==f) lch[gf]=x; 51 else rch[gf]=x; 52 } 53 rch[f]=lch[x]; 54 if(lch[x]) fa[lch[x]]=f; 55 lch[x]=f; 56 update(f); 57 update(x); 58 } 59 inline void Splay(int x,int T) 60 { 61 int f,gf; 62 while(fa[x]!=T) 63 { 64 f=fa[x]; 65 gf=fa[f]; 66 if(gf==T) 67 { 68 if(x==lch[f]) zig(x); 69 else zag(x); 70 break; 71 } 72 if(f==lch[gf]) 73 { 74 if(x==lch[f]) {zig(f);zig(x);} 75 else {zag(x);zig(x);} 76 } 77 else 78 { 79 if(x==lch[f]) {zig(x);zag(x);} 80 else {zag(f);zag(x);} 81 } 82 } 83 } 84 inline int Inner_Find(int x,int p) 85 { 86 while(key[p]!=x) 87 { 88 if(x<key[p]) 89 { 90 if(!lch[p]) break; 91 p=lch[p]; 92 } 93 else 94 { 95 if(!rch[p]) break; 96 p=rch[p]; 97 } 98 } 99 return p; 100 } 101 inline void Inner_Insert(int x,int T) 102 { 103 if(!root[T]) 104 { 105 root[T]=newnode(); 106 key[root[T]]=x; 107 size[root[T]]=rep[root[T]]=1; 108 return; 109 } 110 int k=Inner_Find(x,root[T]); 111 if(x==key[k]) 112 { 113 rep[k]++; 114 size[k]++; 115 } 116 else if(x<key[k]) 117 { 118 lch[k]=newnode(); 119 fa[lch[k]]=k; 120 k=lch[k]; 121 size[k]=rep[k]=1; 122 key[k]=x; 123 } 124 else 125 { 126 rch[k]=newnode(); 127 fa[rch[k]]=k; 128 k=rch[k]; 129 size[k]=rep[k]=1; 130 key[k]=x; 131 } 132 Splay(k,0); 133 root[T]=k; 134 } 135 inline int Find_Max(int p) 136 { 137 while(rch[p]) p=rch[p]; 138 return p; 139 } 140 inline void Inner_Delete(int x,int T,bool rot) 141 { 142 int k; 143 if(!rot) k=Inner_Find(x,root[T]); 144 else k=root[T]; 145 if(rep[k]>1) 146 { 147 rep[k]--; 148 update(k); 149 update(fa[k]); 150 Splay(k,0); 151 root[T]=k; 152 return; 153 } 154 Splay(k,0); 155 root[T]=k; 156 if(lch[k]) 157 { 158 if(rch[k]) 159 { 160 int u=Find_Max(lch[k]); 161 Splay(u,root[T]); 162 root[T]=lch[k]; 163 fa[lch[k]]=0; 164 rch[lch[k]]=rch[k]; 165 fa[rch[k]]=lch[k]; 166 } 167 else 168 { 169 root[T]=lch[k]; 170 fa[lch[k]]=0; 171 } 172 } 173 else if(rch[k]) 174 { 175 root[T]=rch[k]; 176 fa[rch[k]]=0; 177 } 178 else root[T]=0; 179 Discard(k); 180 if(root[T]) update(root[T]); 181 } 182 inline void Outer_Insert(int pos,int x) 183 { 184 int l=1,r=n,p=1,mid; 185 while(l<r) 186 { 187 Inner_Insert(x,p); 188 mid=(l+r)>>1; 189 if(pos<=mid) {r=mid;p<<=1;} 190 else {l=mid+1;p=(p<<1)+1;} 191 } 192 Inner_Insert(x,p); 193 } 194 inline void Outer_Delete(int pos,int x) 195 { 196 int l=1,r=n,p=1,mid; 197 while(l<r) 198 { 199 Inner_Delete(x,p,0); 200 mid=(l+r)>>1; 201 if(pos<=mid) {r=mid;p<<=1;} 202 else {l=mid+1;p=(p<<1)+1;} 203 } 204 Inner_Delete(x,p,0); 205 } 206 inline int Inner_Rank(int T,int x) 207 { 208 int p=root[T],res=0; 209 while(1) 210 { 211 if(!p) return res; 212 if(key[p]==x) return res+size[lch[p]]; 213 if(key[p]<x) 214 { 215 res+=size[lch[p]]+rep[p]; 216 p=rch[p]; 217 } 218 else p=lch[p]; 219 } 220 return res; 221 } 222 inline int Query_Rank(int T,int l,int r,int a,int b,int k) 223 { 224 if(l==a&&r==b) return Inner_Rank(T,k); 225 if(l==r) return 0; 226 int mid=(l+r)>>1; 227 if(b<=mid) return Query_Rank(T*2,l,mid,a,b,k); 228 else if(a>mid) return Query_Rank(T*2+1,mid+1,r,a,b,k); 229 else return Query_Rank(T*2,l,mid,a,mid,k)+Query_Rank(T*2+1,mid+1,r,mid+1,b,k); 230 } 231 inline int Inner_Pre(int T,int x) 232 { 233 int p=root[T],res=-INF; 234 while(p) 235 { 236 if(key[p]<x) 237 { 238 res=max(res,key[p]); 239 p=rch[p]; 240 } 241 else p=lch[p]; 242 } 243 return res; 244 } 245 inline int Query_Pre(int T,int l,int r,int a,int b,int k) 246 { 247 if(l==a&&r==b) return Inner_Pre(T,k); 248 int mid=(l+r)>>1; 249 if(b<=mid) return Query_Pre(T*2,l,mid,a,b,k); 250 else if(a>mid) return Query_Pre(T*2+1,mid+1,r,a,b,k); 251 else return max(Query_Pre(T*2,l,mid,a,mid,k),Query_Pre(T*2+1,mid+1,r,mid+1,b,k)); 252 } 253 inline int Inner_Next(int T,int x) 254 { 255 int p=root[T],res=INF; 256 while(p) 257 { 258 if(key[p]>x) 259 { 260 res=min(res,key[p]); 261 p=lch[p]; 262 } 263 else p=rch[p]; 264 } 265 return res; 266 } 267 inline int Query_Next(int T,int l,int r,int a,int b,int k) 268 { 269 if(l==a&&r==b) return Inner_Next(T,k); 270 int mid=(l+r)>>1; 271 if(b<=mid) return Query_Next(T*2,l,mid,a,b,k); 272 else if(a>mid) return Query_Next(T*2+1,mid+1,r,a,b,k); 273 else return min(Query_Next(T*2,l,mid,a,mid,k),Query_Next(T*2+1,mid+1,r,mid+1,b,k)); 274 } 275 inline int Query_Kth(int a,int b,int k) 276 { 277 int l=1,r=INF,mid,res,c; 278 while(l<=r) 279 { 280 mid=(l+r)>>1; 281 c=Query_Rank(1,1,n,a,b,mid)+1; 282 if(c<=k){l=mid+1;res=mid;} 283 else r=mid-1; 284 } 285 return res; 286 } 287 inline int read(int &u) 288 { 289 int f=1,x=0; 290 char ch=getchar(); 291 for(;!isdigit(ch);ch=getchar()) if(ch==‘-‘) f=-1; 292 for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-‘0‘; 293 u=x*f; 294 } 295 int main() 296 { 297 int m,opt,k,a,b; 298 read(n); 299 read(m); 300 for(int i=1;i<=n;i++) 301 { 302 read(rec[i]); 303 Outer_Insert(i,rec[i]); 304 } 305 while(m--) 306 { 307 scanf("%d",&opt); 308 if(opt==3) read(a),read(k); 309 else read(a),read(b),read(k); 310 switch(opt) 311 { 312 case 1: 313 printf("%d\n",Query_Rank(1,1,n,a,b,k)+1); 314 break; 315 case 2: 316 printf("%d\n",Query_Kth(a,b,k)); 317 break; 318 case 3: 319 Outer_Insert(a,k); 320 Outer_Delete(a,rec[a]); 321 rec[a]=k; 322 break; 323 case 4: 324 printf("%d\n",Query_Pre(1,1,n,a,b,k)); 325 break; 326 case 5: 327 printf("%d\n",Query_Next(1,1,n,a,b,k)); 328 break; 329 } 330 } 331 return 0; 332 }
以上是关于BZOJ3196二逼平衡树树套树的主要内容,如果未能解决你的问题,请参考以下文章