整体二分

把所有询问离线一起二分回答。

跟CDQ分治比较:

CDQ分治是按照中序遍历来解决,整体二分是从上往下。

推荐一个博客

例题洛谷P2617 Dynamic Rankings

  1 #include <cstdio>
  2 #include <algorithm>
  3 #include <cstring>
  4 
  5 const int N = 100010;
  6 
  7 struct Node {
  8     int f, x, y, k, id;
  9     // f = 0  ask  [x, y]  k
 10     // f = 1  change  pos = x  val = y  sum += k
 11     Node(int F = 0, int X = 0, int Y = 0, int K = 0, int ID = 0) {
 12         f = F;
 13         x = X;
 14         y = Y;
 15         k = K;
 16         id = ID;
 17     }
 18 }node[N * 3], t1[N * 3], t2[N * 3];
 19 
 20 int ans[N], ta[N], a[N], n;
 21 char str[3];
 22 
 23 inline void add(int x, int v) {
 24     for(int i = x; i <= n; i += i & (-i)) {
 25         ta[i] += v;
 26     }
 27     return;
 28 }
 29 
 30 inline int getSum(int x) {
 31     int ans = 0;
 32     for(int i = x; i >= 1; i -= i & (-i)) {
 33         ans += ta[i];
 34     }
 35     return ans;
 36 }
 37 
 38 inline void div(int L, int R, int l, int r) {
 39     //printf("[%d %d]  [%d %d] 
", L, R, l, r);
 40     if(L > R || l > r) {
 41         return;
 42     }
 43     if(l == r) {
 44         for(int i = L; i <= R; i++) {
 45             if(node[i].f == 0) {
 46                 ans[node[i].id] = r;
 47             }
 48         }
 49         return;
 50     }
 51     int mid = (l + r) >> 1;
 52     int top1 = 0, top2 = 0;
 53     for(int i = L; i <= R; i++) {
 54         if(node[i].f == 0) { // ask
 55             int t = getSum(node[i].y) - getSum(node[i].x - 1);
 56             if(node[i].k <= t) {
 57                 t1[++top1] = node[i];
 58             }
 59             else {
 60                 node[i].k -= t;
 61                 t2[++top2] = node[i];
 62             }
 63         }
 64         else { // change
 65             if(node[i].y <= mid) {
 66                 add(node[i].x, node[i].k);
 67                 t1[++top1] = node[i];
 68             }
 69             else {
 70                 t2[++top2] = node[i];
 71             }
 72         }
 73     }
 74     for(int i = 1; i <= top1; i++) {
 75         if(t1[i].f) {
 76             add(t1[i].x, -t1[i].k);
 77         }
 78     }
 79     memcpy(node + L, t1 + 1, top1 * sizeof(Node));
 80     memcpy(node + L + top1, t2 + 1, top2 * sizeof(Node));
 81     div(L, L + top1 - 1, l, mid);
 82     div(L + top1, R, mid + 1, r);
 83     return;
 84 }
 85 
 86 int main() {
 87     int m, tot = 0;
 88     scanf("%d%d", &n, &m);
 89     memset(ans, 0x3f, sizeof(ans));
 90     int small = ans[0], large = -ans[0];
 91     for(int i = 1; i <= n; i++) {
 92         scanf("%d", &a[i]);
 93         node[++tot] = Node(1, i, a[i], 1, 0);
 94         small = std::min(small, a[i]);
 95         large = std::max(large, a[i]);
 96     }
 97     for(int i = 1, x, y, k; i <= m; i++) {
 98         scanf("%s", str);
 99         if(str[0] == 'Q') {
100             scanf("%d%d%d", &x, &y, &k);
101             node[++tot] = Node(0, x, y, k, i);
102         }
103         else {
104             scanf("%d%d", &x, &y);
105             node[++tot] = Node(1, x, a[x], -1, 0);
106             node[++tot] = Node(1, x, y, 1, i);
107             a[x] = y;
108             small = std::min(small, y);
109             large = std::max(large, y);
110         }
111     }
112     div(1, tot, small, large);
113     for(int i = 1; i <= m; i++) {
114         if(ans[i] != ans[0]) {
115             printf("%d
", ans[i]);
116         }
117     }
118     return 0;
119 }
AC代码

注意这里对原来的数视作一个插入。对修改视作删除 + 插入,跟CDQ一样。用完树状数组之后要还原也跟CDQ一样。

不用合并区间所以不用归并。注意操作数不是m。

[ZJOI2013]K大数查询

当单点修改变成区间放入一个数的时候,树套树T飞......整体二分就是把树状数组的操作变成区间加,区间求和。线段树即可。

区间覆盖标记的线段树写起来繁琐至极...要注意下传tag如果把覆盖标记覆盖了,那么还要把子节点的覆盖标记传到孙子上。

50000²爆int了...

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 
  5 typedef long long LL;
  6 const int N = 50010;
  7 
  8 struct Node {
  9     int f, x, y, id; // 0 ask 1 change
 10     LL v;
 11 }node[N], t1[N], t2[N];
 12 
 13 LL X[N];
 14 int ans[N], xx, n;
 15 int tag[N * 4], zero[N * 4];
 16 LL sum[N * 4];
 17 
 18 inline void pushdown(int l, int r, int o) {
 19     if(zero[o]) {
 20         zero[o << 1] = zero[o << 1 | 1] = 1;
 21         sum[o << 1] = sum[o << 1 | 1] = 0;
 22         tag[o << 1] = tag[o << 1 | 1] = 0;
 23         zero[o] = 0;
 24     }
 25     if(tag[o]) {
 26         int mid = (l + r) >> 1;
 27         //zero[o << 1] = zero[o << 1 | 1] = 0;
 28         int ls = o << 1, rs = o << 1 | 1;
 29         if(zero[ls]) {
 30             zero[ls] = 0;
 31             if(l < mid) {
 32                 zero[ls << 1] = zero[ls << 1 | 1] = 1;
 33                 sum[ls << 1] = sum[ls << 1 | 1] = 0;
 34                 tag[ls << 1] = tag[ls << 1 | 1] = 0;
 35             }
 36         }
 37         if(zero[rs]) {
 38             zero[rs] = 0;
 39             if(mid + 1 < r) {
 40                 zero[rs << 1] = zero[rs << 1 | 1] = 1;
 41                 sum[rs << 1] = sum[rs << 1 | 1] = 0;
 42                 tag[rs << 1] = tag[rs << 1 | 1] = 0;
 43             }
 44         }
 45         tag[o << 1] += tag[o];
 46         tag[o << 1 | 1] += tag[o];
 47         sum[o << 1] += 1ll * (mid - l + 1) * tag[o];
 48         sum[o << 1 | 1] += 1ll * (r - mid) * tag[o];
 49         tag[o] = 0;
 50     }
 51     return;
 52 }
 53 
 54 void add(int L, int R, int l, int r, int o) {
 55     //printf("add %d %d %d %d 
", L, R, l, r);
 56     if(L <= l && r <= R) {
 57         if(zero[o]) {
 58             zero[o] = 0;
 59             if(l < r) {
 60                 zero[o << 1] = zero[o << 1 | 1] = 1;
 61                 sum[o << 1] = sum[o << 1 | 1] = 0;
 62                 tag[o << 1] = tag[o << 1 | 1] = 0;
 63             }
 64         }
 65         tag[o]++;
 66         sum[o] += (r - l + 1);
 67         //printf("sum %d += %d = %d 
", o, (r - l + 1), sum[o]);
 68         return;
 69     }
 70     pushdown(l, r, o);
 71     int mid = (l + r) >> 1;
 72     if(L <= mid) {
 73         add(L, R, l, mid, o << 1);
 74     }
 75     if(mid < R) {
 76         add(L, R, mid + 1, r, o << 1 | 1);
 77     }
 78     sum[o] = sum[o << 1] + sum[o << 1 | 1];
 79     return;
 80 }
 81 
 82 LL ask(int L, int R, int l, int r, int o) {
 83     //printf("ASK : %d %d %d %d 
", L, R, l, r);
 84     if(L <= l && r <= R) {
 85         //printf("return sum %d = %d 
", o, sum[o]);
 86         return sum[o];
 87     }
 88     pushdown(l, r, o);
 89     int mid = (l + r) >> 1;
 90     LL ans = 0;
 91     if(L <= mid) {
 92         ans += ask(L, R, l, mid, o << 1);
 93     }
 94     if(mid < R) {
 95         ans += ask(L, R, mid + 1, r, o << 1 | 1);
 96     }
 97     return ans;
 98 }
 99 
100 inline void solve(int L, int R, int l, int r) {
101     //printf("solve : %d %d  %d %d
", L, R, l, r);
102     if(L > R) {
103         return;
104     }
105     if(l == r) {
106         for(int i = L; i <= R; i++) {
107             if(node[i].f == 2) {
108                 ans[node[i].id] = r;
109             }
110         }
111         return;
112     }
113     int mid = (l + r) >> 1, top1 = 0, top2 = 0;
114     for(int i = L; i <= R; i++) {
115         if(node[i].f == 2) { // ask
116             LL t = ask(node[i].x, node[i].y, 1, n, 1);
117             //printf("id = %d  t = %d 
", node[i].id, t);
118             if(node[i].v <= t) {
119                 t2[++top2] = node[i];
120             }
121             else {
122                 node[i].v -= t;
123                 t1[++top1] = node[i];
124             }
125         }
126         else {
127             if(node[i].v > mid) {
128                 add(node[i].x, node[i].y, 1, n, 1);
129                 t2[++top2] = node[i];
130             }
131             else {
132                 t1[++top1] = node[i];
133             }
134         }
135     }
136     zero[1] = 1; sum[1] = tag[1] = 0;
137     memcpy(node + L, t1 + 1, top1 * sizeof(Node));
138     memcpy(node + L + top1, t2 + 1, top2 * sizeof(Node));
139     solve(L, L + top1 - 1, l, mid);
140     solve(L + top1, R, mid + 1, r);
141     return;
142 }
143 
144 int main() {
145 
146     int m;
147     scanf("%d%d", &n, &m);
148     memset(ans, -1, sizeof(ans));
149     for(int i = 1; i <= m; i++) {
150         scanf("%d%d%d%lld", &node[i].f, &node[i].x, &node[i].y, &node[i].v);
151         node[i].id = i;
152         if(node[i].f == 1) {
153             X[++xx] = node[i].v;
154         }
155     }
156     std::sort(X + 1, X + xx + 1);
157     xx = std::unique(X + 1, X + xx + 1) - X - 1;
158     for(int i = 1; i <= m; i++) {
159         if(node[i].f == 1) {
160             node[i].v = std::lower_bound(X + 1, X + xx + 1, node[i].v) - X;
161         }
162     }
163     solve(1, m, 1, xx);
164     for(int i = 1; i <= m; i++) {
165         if(ans[i] != ans[0]) {
166             printf("%lld
", X[ans[i]]);
167         }
168     }
169     return 0;
170 }
AC代码

洛谷P1527 矩阵乘法

二维平面的时候用二维树状数组即可。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 
  5 const int N = 510, M = 60010;
  6 
  7 struct Node {
  8     int f, x, y, xx, yy, k, id; /// 0 ask 1 change
  9     Node(int F = 0, int X = 0, int Y = 0, int XX = 0, int YY = 0, int K = 0, int ID = 0) {
 10         f = F;
 11         x = X;
 12         y = Y;
 13         k = K;
 14         xx = XX;
 15         yy = YY;
 16         id = ID;
 17     }
 18 }node[N * N + M], t1[N * N + M], t2[N * N + M]; int tot;
 19 
 20 int X[N * N], xx, a[N][N], n;
 21 int ta[N][N], ans[M];
 22 
 23 inline void add(int x, int y, int v) {
 24     for(int i = x; i <= n; i += i & (-i)) {
 25         for(int j = y; j <= n; j += j & (-j)) {
 26             ta[i][j] += v;
 27         }
 28     }
 29     return;
 30 }
 31 
 32 inline int ask(int x, int y) {
 33     int ans = 0;
 34     for(int i = x; i >= 1; i -= i & (-i)) {
 35         for(int j = y; j >= 1; j -= j & (-j)) {
 36             ans += ta[i][j];
 37         }
 38     }
 39     return ans;
 40 }
 41 
 42 void solve(int L, int R, int l, int r) {
 43     if(L > R) {
 44         return;
 45     }
 46     if(l == r) {
 47         for(int i = L; i <= R; i++) {
 48             if(node[i].f == 0) {
 49                 ans[node[i].id] = r;
 50             }
 51         }
 52         return;
 53     }
 54     int mid = (l + r) >> 1, top1 = 0, top2 = 0;
 55     for(int i = L; i <= R; i++) {
 56         if(node[i].f == 0) { // ask
 57             int x = node[i].x, y = node[i].y;
 58             int xx = node[i].xx, yy = node[i].yy;
 59             int t = ask(xx, yy) - ask(xx, y - 1) - ask(x - 1, yy) + ask(x - 1, y - 1);
 60             if(node[i].k <= t) {
 61                 t1[++top1] = node[i];
 62             }
 63             else {
 64                 node[i].k -= t;
 65                 t2[++top2] = node[i];
 66             }
 67         }
 68         else { // change
 69             if(node[i].k <= mid) {
 70                 add(node[i].x, node[i].y, 1);
 71                 t1[++top1] = node[i];
 72             }
 73             else {
 74                 t2[++top2] = node[i];
 75             }
 76         }
 77     }
 78     for(int i = 1; i <= top1; i++) {
 79         if(t1[i].f) {
 80             add(t1[i].x, t1[i].y, -1);
 81         }
 82     }
 83     memcpy(node + L, t1 + 1, top1 * sizeof(Node));
 84     memcpy(node + L + top1, t2 + 1, top2 * sizeof(Node));
 85     solve(L, L + top1 - 1, l, mid);
 86     solve(L + top1, R, mid + 1, r);
 87     return;
 88 }
 89 
 90 int main() {
 91     int q;
 92     scanf("%d%d", &n, &q);
 93     memset(ans, 0x7f, sizeof(ans));
 94     for(int i = 1; i <= n; i++) {
 95         for(int j = 1; j <= n; j++) {
 96             scanf("%d", &a[i][j]);
 97             node[++tot] = Node(1, i, j, 0, 0, a[i][j], 0);
 98             X[tot] = a[i][j];
 99         }
100     }
101     std::sort(X + 1, X + tot + 1);
102     int xx = std::unique(X + 1, X + tot + 1) - X - 1;
103     for(int i = 1; i <= tot; i++) {
104         node[i].k = std::lower_bound(X + 1, X + xx + 1, node[i].k) - X;
105     }
106     for(int i = 1; i <= q; i++) {
107         ++tot;
108         scanf("%d%d%d%d%d", &node[tot].x, &node[tot].y, &node[tot].xx, &node[tot].yy, &node[tot].k);
109         node[tot].id = i;
110     }
111     solve(1, tot, 1, xx);
112     for(int i = 1; i <= q; i++) {
113         if(ans[i] != ans[0]) {
114             printf("%d
", X[ans[i]]);
115         }
116     }
117     return 0;
118 }
AC代码
原文地址:https://www.cnblogs.com/huyufeifei/p/10397097.html