[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)

时间: 2024-10-21 16:09:26

[Tyvj 1730] 二逼平衡树的相关文章

bzoj 3196/ Tyvj 1730 二逼平衡树 (线段树套平衡树)

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,

【BZOJ 3196】Tyvj 1730 二逼平衡树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 842  Solved: 350 [Submit][Status] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排名 2.查询区间内排名为k的值 3.修改某一位值上的数值 4.查询k在区间内的前驱(前驱定义为小于x,且最大的数) 5.查询k在区间内的后继(后继定义为大于x,

BZOJ 3196: Tyvj 1730 二逼平衡树( 树套树 )

这道题做法应该很多吧.... 我用了线段树套treap.... -------------------------------------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<cstdlib> #include<ios

Bzoj3196 Tyvj 1730 二逼平衡树

Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3350  Solved: 1324 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行

【线段树套平衡树】【pb_ds】bzoj3196 Tyvj 1730 二逼平衡树

线段树套pb_ds里的平衡树,在洛谷OJ上测试,后三个测试点TLE #include<cstdio> #include<algorithm> #include<ext/pb_ds/assoc_container.hpp> #include<ext/pb_ds/tree_policy.hpp> #define N 50010 #define INF 2147483647 using namespace std; using namespace __gnu_pb

bzoj 3196: Tyvj 1730 二逼平衡树

我操,,,,我记得这个sb题,,搞了一整天,(吐槽,本来开心去洛谷提交,结果不一样,mdzz) 树套树,,,各种套... 都是在区间内最基本的查询 1 #include<bits/stdc++.h> 2 #define N 100005 3 #define LL long long 4 #define inf 0x3f3f3f3f 5 using namespace std; 6 inline int ra() 7 { 8 int x=0,f=1; char ch=getchar(); 9 w

[bzoj3196][Tyvj 1730][二逼平衡树] (线段树套treap)

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在区间

【BZOJ3196】Tyvj 1730 二逼平衡树

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]的排名

BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <string> #include <alg