BZOJ 2738 子矩阵第k大 | 二维树状数组 整体二分 分治
2017-12-05 20:05
441 查看
BZOJ 2738 “矩阵乘法”(子矩阵第k大)
题意
给出一个矩阵,多次询问子矩阵中第k大的数是多少。
题解
我做这道题之前先照着这道题出了一道题,是这道题的一维版本,在这里:https://vijos.org/d/contest/p/5a26541bd3d8a11cef1706aa。
思路是这样的:二分答案mid,将所有小于mid的位置都在树状数组上 +1,对于每个询问,如果子矩阵所有”+1“之和 >= 这个询问的k,则把询问划分到”左边那一组”,否则划分到“右边那一组”,之后对它们分别处理。
核心代码:
void solve(int l, int r, int ql, int qr){ if(ql > qr) return; if(l == r){ for(int i = ql; i <= qr; i++) ans[q[i].id] = a[l].val; return; } int mid = (l + r) >> 1, cnt = 0; for(int i = l; i <= mid; i++) add(a[i].x, a[i].y, 1); for(int i = ql; i <= qr; i++){ sum[i] = ask(q[i]); if(sum[i] >= q[i].k) cnt++; } for(int i = ql, pl = ql, pr = ql + cnt; i <= qr; i++) if(sum[i] >= q[i].k) tmp[pl++] = q[i]; else q[i].k -= sum[i], tmp[pr++] = q[i]; for(int i = ql; i <= qr; i++) q[i] = tmp[i]; for(int i = l; i <= mid; i++) add(a[i].x, a[i].y, -1); solve(l, mid, ql, ql + cnt - 1); solve(mid + 1, r, ql + cnt, qr); }
完整代码:
#include <cstdio> #include <cmath> #include <cstring> #include <algorithm> #define space putchar(' ') #define enter putchar('\n') using namespace std; typedef long long ll; template <class T> void read(T &x){ char c; bool op = 0; while(c = getchar(), c < '0' || c > '9') if(c == '-') op = 1; x = c - '0'; while(c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; if(op) x = -x; } template <class T> void write(T x){ if(x < 0) putchar('-'), x = -x; if(x >= 10) write(x / 10); putchar('0' + x % 10); } const int N = 505, M = 60005; int n, m, tr , ans[M], idx, sum[M]; struct element { int x, y, val; bool operator < (const element &b) const{ return val < b.val; } } a[N*N]; struct query { int id, xa, ya, xb, yb, k; } q[M], tmp[M]; void add(int x, int y, int val){ for(int px = x; px <= n; px += px & -px) for(int py = y; py <= n; py += py & -py) tr[px][py] += val; } int single_ask(int x, int y){ int ret = 0; for(int px = x; px; px -= px & -px) for(int py = y; py; py -= py & -py) ret += tr[px][py]; return ret; } int ask(query Q){ return single_ask(Q.xb, Q.yb) - single_ask(Q.xa - 1, Q.yb) - single_ask(Q.xb, Q.ya - 1) + single_ask(Q.xa - 1, Q.ya - 1); } void solve(int l, int r, int ql, int qr){ if(ql > qr) return; if(l == r){ for(int i = ql; i <= qr; i++) ans[q[i].id] = a[l].val; return; } int mid = (l + r) >> 1, cnt = 0; for(int i = l; i <= mid; i++) add(a[i].x, a[i].y, 1); for(int i = ql; i <= qr; i++){ sum[i] = ask(q[i]); if(sum[i] >= q[i].k) cnt++; } for(int i = ql, pl = ql, pr = ql + cnt; i <= qr; i++) if(sum[i] >= q[i].k) tmp[pl++] = q[i]; else q[i].k -= sum[i], tmp[pr++] = q[i]; for(int i = ql; i <= qr; i++) q[i] = tmp[i]; for(int i = l; i <= mid; i++) add(a[i].x, a[i].y, -1); solve(l, mid, ql, ql + cnt - 1); solve(mid + 1, r, ql + cnt, qr); } int main(){ read(n), read(m); for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) a[++idx].x = i, a[idx].y = j, read(a[idx].val); sort(a + 1, a + idx + 1); for(int i = 1; i <= m; i++) q[i].id = i, read(q[i].xa), read(q[i].ya), read(q[i].xb), read(q[i].yb), read(q[i].k); solve(1, idx, 1, m); for(int i = 1; i <= m; i++) write(ans[i]), enter; return 0; }
相关文章推荐
- BZOJ 2738 矩阵乘法 整体二分+二维树状数组
- 【整体二分+二维树状数组】BZOJ2738 矩阵乘法
- [BZOJ2738]矩阵乘法-二维树状数组-整体二分
- BZOJ 2738: 矩阵乘法 整体二分 二维树状数组
- [BZOJ2738]矩阵乘法 整体二分+二维树状数组
- 【BZOJ2738】矩阵乘法(整体二分+二位树状数组)
- 【BZOJ2738】矩阵乘法 [整体二分][树状数组]
- bzoj 2738: 矩阵乘法 (整体二分+二维树状数组)
- BZOJ2527 [Poi2011]Meteors 【整体二分 + 树状数组】
- 【BZOJ】3110 [Zjoi2013]K大数查询 整体二分+树状数组 || 树套树
- BZOJ3110[Zjoi2013]K大数查询(树状数组+整体二分)
- [BZOJ4009][HNOI2015]接水果-整体二分-树状数组-扫描线
- BZOJ 2738 矩阵乘法(整体二分+二维树状数组)
- [BZOJ2738]矩阵乘法(整体二分+二维bit)
- bzoj 2527: [Poi2011]Meteors (树状数组+整体二分)
- [BZOJ2527][Poi2011][整体二分][树状数组]Meteors
- bzoj2738: 矩阵乘法【整体二分+二维树状数组】
- bzoj 2527 Meteors - 整体二分 - 树状数组
- 【整体二分+树状数组】BZOJ2527 [Poi2011]Meteors
- 【清澄A1333】【整体二分+二维树状数组】矩阵乘法(梁盾)