I K小数查询

链接:https://ac.nowcoder.com/acm/contest/3979/I
来源:牛客网

题目描述

 

 

思路:题目乍一看让我一开始想往权值线段树加主席树的方向思考,可是又有修改操作,导致我无从下手;

然后看了别人博客,大多都是采用分块的方式

在本代码里,每一块的大小为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  (摘自此博客)

 

posted @ 2020-03-11 19:59  古比  阅读(280)  评论(0编辑  收藏  举报