首页 > 代码库 > BZOJ 3110:[Zjoi2013]K大数查询(整体二分)

BZOJ 3110:[Zjoi2013]K大数查询(整体二分)

http://www.lydsy.com/JudgeOnline/problem.php?id=3110

题意:……

思路:其实和之前POJ那道题差不多,只不过是换成区间更新,而且是第k大不是第k小,第k大是降序的第k个,在二分询问的时候需要注意和第k小的不同细节。

树状数组比线段树快了几倍,所以说树状数组区间更新区间查询是一个值得学的姿势啊。

线段树:

 1 //9028 kb    7484 ms
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 #define N 50010
 7 #define lson rt<<1, l, m
 8 #define rson rt<<1|1, m + 1, r
 9 typedef long long LL;
10 struct P {
11     int type, l, r, id; LL val;
12     P () {}
13     P (int type, int l, int r, LL val, int id) : type(type), l(l), r(r), val(val), id(id) {}
14 } q[N], lq[N], rq[N], qq[N];
15 LL tree[N<<2], lazy[N<<2], ans[N];
16 int n;
17 
18 void pushup(int rt) { tree[rt] = tree[rt<<1|1] + tree[rt<<1]; }
19 
20 void pushdown(int rt, int len) {
21     if(lazy[rt]) {
22         lazy[rt<<1] += lazy[rt]; lazy[rt<<1|1] += lazy[rt];
23         tree[rt<<1] += lazy[rt] * (len - (len >> 1)); tree[rt<<1|1] += lazy[rt] * (len >> 1);
24         lazy[rt] = 0;
25     }
26 }
27 
28 void update(int rt, int l, int r, int L, int R, int val) {
29     if(L <= l && r <= R) {
30         tree[rt] += (r - l + 1) * val; // 居然漏了+1
31         lazy[rt] += val; return ;
32     }
33     pushdown(rt, r - l + 1);
34     int m = (l + r) >> 1;
35     if(L <= m) update(lson, L, R, val);
36     if(m < R) update(rson, L, R, val);
37     pushup(rt);
38 }
39 
40 LL query(int rt, int l, int r, int L, int R) {
41     if(L <= l && r <= R) return tree[rt];
42     pushdown(rt, r - l + 1);
43     int m = (l + r) >> 1;
44     LL ans = 0;
45     if(L <= m) ans += query(lson, L, R);
46     if(m < R) ans += query(rson, L, R);
47     return ans;
48 }
49 
50 void Solve(int l, int r, int lask, int rask) {
51     if(rask < lask || r < l) return ;
52     if(l == r) { for(int i = lask; i <= rask; i++) if(q[i].type == 2) ans[q[i].id] = l; return ; }
53     int mid = (l + r) >> 1, lcnt = 0, rcnt = 0;
54     for(int i = lask; i <= rask; i++) {
55         if(q[i].type == 1) {
56             if(mid >= q[i].val) { // 第k大 = 降序第k个,只更新比当前二分的答案大的
57                 lq[++lcnt] = q[i];
58             } else {
59                 rq[++rcnt] = q[i];
60                 update(1, 1, n, q[i].l, q[i].r, 1);
61             }
62         } else {
63             LL num = query(1, 1, n, q[i].l, q[i].r);
64             if(num >= q[i].val) rq[++rcnt] = q[i];
65             else {
66                 q[i].val -= num;
67                 lq[++lcnt] = q[i];
68             }
69         }
70     }
71     for(int i = lask; i <= rask; i++) if(q[i].type == 1 && mid < q[i].val) update(1, 1, n, q[i].l, q[i].r, -1);
72     for(int i = 1; i <= lcnt; i++) q[i+lask-1] = lq[i];
73     for(int i = 1; i <= rcnt; i++) q[i+lask+lcnt-1] = rq[i];
74     Solve(l, mid, lask, lask + lcnt - 1);
75     Solve(mid + 1, r, lask + lcnt, rask);
76 }
77 
78 int main() {
79     int m, a, b, c, d, ins = 0, ask = 0;
80     scanf("%d%d", &n, &m);
81     for(int i = 1; i <= m; i++) {
82         scanf("%d%d%d%d", &a, &b, &c, &d);
83         if(a == 1) q[i] = P(a, b, c, d, ++ins);
84         else q[i] = P(a, b, c, d, ++ask);
85     }
86     Solve(1, n, 1, m);
87     for(int i = 1; i <= ask; i++)
88         printf("%lld\n", ans[i]);
89     return 0;
90 }

树状数组:

 1 //1828ms    6.7MB
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 #define N 50010
 7 #define lson rt<<1, l, m
 8 #define rson rt<<1|1, m + 1, r
 9 typedef long long LL;
10 struct P {
11     int type, l, r, id; LL val;
12     P () {}
13     P (int type, int l, int r, LL val, int id) : type(type), l(l), r(r), val(val), id(id) {}
14 } q[N], lq[N], rq[N], qq[N];
15 LL bit[2][N], ans[N];
16 int n;
17 
18 int lowbit(int x) { return x & (-x); }
19 void Add(int i, int x, int w) { while(x <= n) bit[i][x] += w, x += lowbit(x); }
20 LL Sum(int i, int x) { LL ans = 0; while(x) ans += bit[i][x], x -= lowbit(x); return ans; }
21 void update(int l, int r, int w) {
22     Add(0, l, w); Add(0, r + 1, -w); Add(1, l, w * l); Add(1, r + 1, -w * (r + 1));
23 }
24 LL query(int l, int r) {
25     LL lsum = Sum(0, l - 1) * l - Sum(1, l - 1);
26     LL rsum = Sum(0, r) * (r + 1) - Sum(1, r);
27     return rsum - lsum;
28 }
29 
30 void Solve(int l, int r, int lask, int rask) {
31     if(rask < lask || r < l) return ;
32     if(l == r) { for(int i = lask; i <= rask; i++) if(q[i].type == 2) ans[q[i].id] = l; return ; }
33     int mid = (l + r) >> 1, lcnt = 0, rcnt = 0;
34     for(int i = lask; i <= rask; i++) {
35         if(q[i].type == 1) {
36             if(mid >= q[i].val) { // 第k大 = 降序第k个,只更新比当前二分的答案大的
37                 lq[++lcnt] = q[i];
38             } else {
39                 rq[++rcnt] = q[i];
40                 update(q[i].l, q[i].r, 1);
41             }
42         } else {
43             LL num = query(q[i].l, q[i].r);
44             if(num >= q[i].val) rq[++rcnt] = q[i];
45             else {
46                 q[i].val -= num;
47                 lq[++lcnt] = q[i];
48             }
49         }
50     }
51     for(int i = lask; i <= rask; i++) if(q[i].type == 1 && mid < q[i].val) update(q[i].l, q[i].r, -1);
52     for(int i = 1; i <= lcnt; i++) q[i+lask-1] = lq[i];
53     for(int i = 1; i <= rcnt; i++) q[i+lask+lcnt-1] = rq[i];
54     Solve(l, mid, lask, lask + lcnt - 1);
55     Solve(mid + 1, r, lask + lcnt, rask);
56 }
57 
58 int main() {
59     int m, a, b, c, d, ins = 0, ask = 0;
60     scanf("%d%d", &n, &m);
61     for(int i = 1; i <= m; i++) {
62         scanf("%d%d%d%d", &a, &b, &c, &d);
63         if(a == 1) q[i] = P(a, b, c, d, ++ins);
64         else q[i] = P(a, b, c, d, ++ask);
65     }
66     Solve(1, n, 1, m);
67     for(int i = 1; i <= ask; i++)
68         printf("%lld\n", ans[i]);
69     return 0;
70 }

 

BZOJ 3110:[Zjoi2013]K大数查询(整体二分)