BZOJ 3110:[Zjoi2013]K大数查询(整体二分)
Posted Shadowdsp
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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大数查询(整体二分)的主要内容,如果未能解决你的问题,请参考以下文章