先来一发题面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 5Sample Output
2 4 3 4 9Hint
n,m<=50000 保证有序序列所有值在任何时刻满足[0,10^8]但是询问的数未必
这题正解似乎是树套树(线段树套平衡树)
然而我用分块大法水过去了233
分块的话思路还是比较明确的,比如对于求排名操作(操作1),对于两端的块我们可以选择直接暴力查询比$key$值小的值的个数,中间的完整块可以选择二分查找($std::lower\_bound$)来得出比$key$小的元素个数,累加起来加上1就是答案了.
求K大的话比较麻烦,要二分第K大的值然后用求排名操作来检验...
修改直接暴力修改不解释
前驱/后继则可以用上面求排名的方式来查找,不同的是对于比$key$小/大的元素不应累加而是求最大/小值.
然后就到了袋马时间~(突然感觉好草率啊QwQ)
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)