[BZOJ2738]矩阵乘法
2738: 矩阵乘法
Time Limit: 20 Sec Memory Limit: 256 MB Submit: 1629 Solved: 710 [Submit][Status][Discuss]Description
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
Input
第一行两个数N,Q,表示矩阵大小和询问组数; 接下来N行N列一共N*N个数,表示这个矩阵; 再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。
Output
对于每组询问输出第K小的数。
Sample Input
2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3
2 1
3 4
1 2 1 2 1
1 1 2 2 3
Sample Output
1
3
3
HINT
矩阵中数字是109以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
整体二分,二维树状数组维护
国庆作业还没做要炸了。。。有时间具体写
Update:
把数字看成插入按照权值排序
然后二分答案,将权值小于等于二分值的全部插入
对于一个询问如果在区间内已经有足够多的数那么就可行
插入和删除可以用二维树状数组维护
#pragma GCC optimize ("O2") #include <cstdio> #include <algorithm> using namespace std; char buf[10000000], *ptr = buf - 1; inline int readint(){ int n = 0; while(*++ptr < '0' || *ptr > '9'); while(*ptr >= '0' && *ptr <= '9') n = (n << 1) + (n << 3) + (*ptr++ & 15); return n; } const int maxn = 500 + 10, maxq = 60000 + 10; int N, Q; int Fen[maxn][maxn] = {0}; inline void Update(const int &x, const int &y, const int &val){ for(int i = x; i <= N; i += i & -i) for(int j = y; j <= N; j += j & -j) Fen[i][j] += val; } inline int Query(const int &x, const int &y){ int s = 0; for(int i = x; i; i -= i & -i) for(int j = y; j; j -= j & -j) s += Fen[i][j]; return s; } struct Insert{ int val, x, y; Insert(){} Insert(int _v, int _x, int _y): val(_v), x(_x), y(_y){} bool operator < (const Insert &a) const { return val < a.val; } }a[maxn * maxn]; int num_cnt = 0; struct Question{ int x1, y1, x2, y2, k; void read(){ x1 = readint(); y1 = readint(); x2 = readint(); y2 = readint(); k = readint(); } }q[maxq]; inline int Query(const Question &t){ return Query(t.x2, t.y2) + Query(t.x1 - 1, t.y1 - 1) - Query(t.x1 - 1, t.y2) - Query(t.x2, t.y1 - 1); } int ans[maxq]; int T = 0; int id[maxq], tmp[maxq]; bool mark[maxq]; void solve(int ql, int qr, int vl, int vr){ if(ql > qr || vl == vr) return; int mid = vl + vr >> 1; while(T < N * N && a[T + 1].val <= mid){ T++; Update(a[T].x, a[T].y, 1); } while(T && a[T].val > mid){ Update(a[T].x, a[T].y, -1); T--; } int cnt = 0; for(int i = ql; i <= qr; i++) if(Query(q[id[i]]) >= q[id[i]].k){ mark[i] = true; ans[id[i]] = mid; cnt++; } else mark[i] = false; int l1 = ql, l2 = ql + cnt; for(int i = ql; i <= qr; i++) if(mark[i]) tmp[l1++] = id[i]; else tmp[l2++] = id[i]; for(int i = ql; i <= qr; i++) id[i] = tmp[i]; solve(ql, l1 - 1, vl, mid); solve(l1, qr, mid + 1, vr); } int main(){ buf[fread(buf, sizeof(char), sizeof(buf), stdin)] = 0; N = readint(); Q = readint(); for(int i = 1; i <= N; i++) for(int j = 1; j <= N; j++) a[++num_cnt] = Insert(readint(), i, j); sort(a + 1, a + num_cnt + 1); for(int i = 1; i <= Q; i++) q[i].read(); for(int i = 1; i <= Q; i++) id[i] = i; solve(1, Q, 0, a[num_cnt].val + 1); for(int i = 1; i <= Q; i++) printf("%d\n", ans[i]); return 0; }