I K小数查询
链接:https://ac.nowcoder.com/acm/contest/3979/I
来源:牛客网
题目描述
![](https://img2020.cnblogs.com/i-beta/1797462/202003/1797462-20200311193811029-113081394.png)
思路:题目乍一看让我一开始想往权值线段树加主席树的方向思考,可是又有修改操作,导致我无从下手;
然后看了别人博客,大多都是采用分块的方式
在本代码里,每一块的大小为sqrt(n);
我们将总的分块,然后用2个数组参数去描述分块信息:L【i】 R【i】 来描述第i块的左右端点;
然后将块内的数据排序;
对于更新操作:我们将左端点和右端点所属块整个遍历一遍,更新值然后排序;
为什么单独更新这两块?因为更新操作八成是不能涵盖这两端点所属块,所以就直接更新了
然后能够涵盖整个块的,就是在l r之间的其他块, 我们用一个懒惰节点去标记,直接更新带过即可(等到查询操作再来改变)
这样子下来,倘若块的大小为k 则修改操作的复杂度为 2*k*log(k)(更新两端点所在块+排序)+k(遍历lr中间的块)
对于查询操作:我们采用二分的方式,枚举答案,判断依据:得出来的ans是否大于等于k
其余操作大体跟更新类似;
我们将左右端点所属块遍历一遍,更新答案(2*k)
遍历中间区间,倘若中间区间的懒惰值小于等于待定答案,我们就整个区间都加上,
反之,则遍历整个区间,找出符合的答案数; 复杂度大致为(logk*k) logk为lower_bound操作,k为块的个数;
所以查询复杂度大致为:(2*k+logk*k)*log n; k=sqrt(n)
1 #include<bits/stdc++.h> 2 #define rint register int 3 #define deb(x) cerr<<#x<<" = "<<(x)<<'\n'; 4 using namespace std; 5 typedef long long ll; 6 using pii = pair <int,int>; 7 const int maxn = 8e4 + 5; 8 int n, m, a[maxn]; 9 int size, bnum, lz[maxn]; 10 int L[maxn], R[maxn]; 11 vector <int> v[maxn]; 12 13 inline int get_id(int x){ 14 return x / size; 15 } 16 17 inline void update(int l, int r, int x){ 18 int id = get_id(l); 19 if(L[id] < l){ 20 v[id].clear(); 21 for(int i=L[id]; i<=R[id]; i++){ 22 a[i] = min(a[i], lz[id]); 23 if(i >= l && i <= r) a[i] = min(a[i], x); 24 v[id].push_back(a[i]); 25 } 26 sort(v[id].begin(), v[id].end()); 27 id++; 28 } 29 if(id >= bnum) return; 30 while(R[id]<=r && id<bnum){ 31 lz[id] = min(lz[id], x); 32 id++; 33 } 34 35 if(L[id]>r || id>=bnum) return; 36 v[id].clear(); 37 for(int i=L[id]; i<=R[id]; i++){ 38 a[i] = min(a[i], lz[id]); 39 if(i >= l && i <= r) a[i] = min(a[i], x); 40 v[id].push_back(a[i]); 41 } 42 sort(v[id].begin(), v[id].end()); 43 } 44 45 inline int ck(int l, int r, int k){ 46 int id = get_id(l), res = 0; 47 if(L[id] < l){ 48 for(int i=l; i<=min(R[id], r); i++){ 49 a[i] = min(a[i], lz[id]); 50 if(a[i] <= k) res++; 51 } 52 id++; 53 } 54 if(id >= bnum) return res; 55 while(R[id]<=r && id<bnum){ 56 if(lz[id] <= k) res += R[id] - L[id] + 1; 57 else res += upper_bound(v[id].begin(), v[id].end(), k) - v[id].begin(); 58 id++; 59 } 60 if(L[id]>r || id>=bnum) return res; 61 for(int i=L[id]; i<=min(R[id], r); i++){ 62 a[i] = min(a[i], lz[id]); 63 if(a[i] <= k) res++; 64 } 65 return res; 66 } 67 68 inline int query(int L, int R, int k){ 69 int l = 1, r = 1e9, mid; 70 while(l <= r){ 71 mid = l + r >> 1; 72 if(ck(L, R, mid) >= k) r = mid - 1; 73 else l = mid + 1; 74 } 75 return l; 76 } 77 78 int main() { 79 scanf("%d%d", &n, &m); 80 for(int i=0; i<n; i++) scanf("%d", a+i); 81 size = sqrt(n), bnum = (n - 1) / size + 1; 82 for(int i=0; i<bnum; i++){ 83 lz[i] = 0x3f3f3f3f; 84 L[i] = i * size, R[i] = i * size + size - 1; 85 if(i == bnum - 1) R[i] = n - 1; 86 for(int j=L[i]; j<=R[i]; j++) v[i].push_back(a[j]); 87 sort(v[i].begin(), v[i].end()); 88 } 89 while(m--){ 90 int op, l, r, k; 91 scanf("%d%d%d%d", &op, &l, &r, &k); 92 l--, r--; 93 if(op == 1) update(l, r, k); 94 else printf("%d\n", query(l, r, k)); 95 } 96 }
https://blog.csdn.net/Scar_Halo/article/details/104095690 (摘自此博客)