首页 > 代码库 > [Tyvj 1730] 二逼平衡树

[Tyvj 1730] 二逼平衡树

先来一发题面QwQ

[TYVJ1730]二逼平衡树

Time Limit:2 s   Memory Limit:512 MB

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

Sample Output

2
4
3
4
9

Hint

n,m<=50000   保证有序序列所有值在任何时刻满足[0,10^8]但是询问的数未必

这题正解似乎是树套树(线段树套平衡树)

然而我用分块大法水过去了233

分块的话思路还是比较明确的,比如对于求排名操作(操作1),对于两端的块我们可以选择直接暴力查询比$key$值小的值的个数,中间的完整块可以选择二分查找($std::lower\_bound$)来得出比$key$小的元素个数,累加起来加上1就是答案了.

求K大的话比较麻烦,要二分第K大的值然后用求排名操作来检验...

修改直接暴力修改不解释

前驱/后继则可以用上面求排名的方式来查找,不同的是对于比$key$小/大的元素不应累加而是求最大/小值.

然后就到了袋马时间~(突然感觉好草率啊QwQ)

GitHub:BlockSearch

技术分享
  1 #include <cmath>
  2 #include <cstdio>
  3 #include <cctype>
  4 #include <cstring>
  5 #include <cstdlib>
  6 #include <iostream>
  7 #include <algorithm>
  8 
  9 const int MAXN=50010;
 10 const int MAXB=230;
 11 const int INF=0x7FFFFFFF;
 12 
 13 int n,m;
 14 int endSize;
 15 int blockNum;
 16 int blockSize;
 17 int data[MAXN];
 18 int block[MAXN][MAXB];
 19 
 20 void Initialize();
 21 void FastRead(int&);
 22 void Modify(int,int);
 23 int Kth(int,int,int);
 24 int Rank(int,int,int);
 25 int Predecessor(int,int,int);
 26 int Successor(int,int,int);
 27 
 28 int main(){
 29     int opt,l,r,num;
 30     Initialize();
 31     for(int i=0;i<m;i++){
 32         scanf("%d",&opt);
 33         if(opt==1){
 34             FastRead(l);
 35             FastRead(r);
 36             FastRead(num);
 37             printf("%d\n",Rank(l-1,r-1,num));
 38         }
 39         else if(opt==2){
 40             FastRead(l);
 41             FastRead(r);
 42             FastRead(num);
 43             printf("%d\n",Kth(l-1,r-1,num));
 44         }
 45         else if(opt==3){
 46             FastRead(l);
 47             FastRead(num);
 48             Modify(l-1,num);
 49         }
 50         else if(opt==4){
 51             FastRead(l);
 52             FastRead(r);
 53             FastRead(num);
 54             printf("%d\n",Predecessor(l-1,r-1,num));
 55         }
 56         else{
 57             FastRead(l);
 58             FastRead(r);
 59             FastRead(num);
 60             printf("%d\n",Successor(l-1,r-1,num));
 61         }
 62     }
 63     return 0;
 64 }
 65 
 66 inline int Rank(int l,int r,int key){
 67     int lb=l/blockSize;
 68     int rb=r/blockSize;
 69     int ans=1;
 70     if(lb==rb){
 71         for(int i=l;i<=r;i++){
 72             if(data[i]<key){
 73                 ans++;
 74             }
 75         }
 76     }
 77     else{
 78         for(int i=l;i<(lb+1)*blockSize;i++){
 79             if(data[i]<key){
 80                 ans++;
 81             }
 82         }
 83         for(int i=rb*blockSize;i<=r;i++){
 84             if(data[i]<key){
 85                 ans++;
 86             }
 87         }
 88         for(int i=lb+1;i<rb;i++){
 89             ans+=std::lower_bound(block[i],block[i]+blockSize,key)-block[i];
 90         }
 91     }
 92     return ans;
 93 }
 94 
 95 inline int Kth(int l,int r,int pos){
 96     int L=-1;
 97     int R=100000010;
 98     while(R-L>1){
 99         int mid=(L+R)>>1;
100         if(Rank(l,r,mid)>pos)
101             R=mid;
102         else
103             L=mid;
104     }
105     return R-1;
106 }
107 
108 inline void Modify(int pos,int key){
109     if(data[pos]==key)
110         return;
111     int* thisBlock=block[pos/blockSize];
112     int old=data[pos];
113     int size=(pos/blockSize)==blockNum?endSize:blockSize;
114     data[pos]=key;
115     pos=std::lower_bound(thisBlock,thisBlock+size,old)-thisBlock;
116     thisBlock[pos]=key;
117     std::sort(thisBlock,thisBlock+size);
118 }
119 
120 inline int Predecessor(int l,int r,int key){
121     int lb=l/blockSize;
122     int rb=r/blockSize;
123     int ans=-INF;
124     if(lb==rb){
125         for(int i=l;i<=r;i++){
126             if(data[i]<key)
127                 ans=std::max(ans,data[i]);
128         }
129     }
130     else{
131         for(int i=l;i<(lb+1)*blockSize;i++){
132             if(data[i]<key)
133                 ans=std::max(ans,data[i]);
134         }
135         for(int i=rb*blockSize;i<=r;i++){
136             if(data[i]<key)
137                 ans=std::max(ans,data[i]);
138         }
139         for(int i=lb+1;i<rb;i++){
140             int pos=std::lower_bound(block[i],block[i]+blockSize,key)-block[i];
141             if(pos>0)
142                 ans=std::max(ans,block[i][pos-1]);
143         }
144     }
145     return ans;
146 }
147 
148 inline int Successor(int l,int r,int key){
149     int lb=l/blockSize;
150     int rb=r/blockSize;
151     int ans=INF;
152     if(lb==rb){
153         for(int i=l;i<=r;i++)
154             if(data[i]>key)
155                 ans=std::min(ans,data[i]);
156     }
157     else{
158         for(int i=l;i<(lb+1)*blockSize;i++){
159             if(data[i]>key)
160                 ans=std::min(ans,data[i]);
161         }
162         for(int i=rb*blockSize;i<=r;i++){
163             if(data[i]>key)
164                 ans=std::min(ans,data[i]);
165         }
166         for(int i=lb+1;i<rb;i++){
167             int pos=std::upper_bound(block[i],block[i]+blockSize,key)-block[i];
168             if(pos<blockSize)
169                 ans=std::min(ans,block[i][pos]);
170         }
171     }
172     return ans;
173 }
174 
175 void Initialize(){
176 #ifndef ASC_LOCAL
177     freopen("psh.in","r",stdin);
178     freopen("psh.out","w",stdout);
179 #endif
180     FastRead(n);
181     FastRead(m);
182     blockSize=sqrt(n);
183     for(int i=0;i<n;i++){
184         FastRead(data[i]);
185         block[blockNum][endSize]=data[i];
186         if(++endSize==blockSize){
187             blockNum++;
188             endSize=0;
189         }
190     }
191     for(int i=0;i<blockNum;i++)
192         std::sort(block[i],block[i]+blockSize);
193     if(endSize!=0)
194         std::sort(block[blockNum],block[blockNum]+endSize);
195 }
196 
197 inline void FastRead(int& target){
198     target=0;
199     register char ch=getchar();
200     bool neg=false;
201     while(!isdigit(ch)){
202         if(ch==-)
203             neg=true;
204         ch=getchar();
205     }
206     while(isdigit(ch)){
207         target=target*10+ch-0;
208         ch=getchar();
209     }
210     if(neg)
211         target=-target;
212 }
Backup: Block Search

然后图包时间233(拿图至少评论一下吼不吼哇QwQ)

技术分享

 

[Tyvj 1730] 二逼平衡树