矩阵乘法 BZOJ 2738
矩阵乘法
【问题描述】
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
【输入格式】
第一行两个数N,Q,表示矩阵大小和询问组数;
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。
【输出格式】
对于每组询问输出第K小的数。
【样例输入】
2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3
【样例输出】
1
3
【样例说明】
矩阵中数字是109以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
题解:
将每个点储存下来,排序一下,和询问进行二分
我们将小于等于当前枚举的答案(即为mid)的点加入树状数组
对于区间内的询问,查询子矩阵内的小于等于mid的个数,如果大于等于这个询问要求的k,将其放置在左区间,表示第k小在l到mid之间
否则放置在右区间,表示第k小在mid+1到r之间
1 #include<cmath>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #include<iostream>
6 #include<algorithm>
7 using namespace std;
8 inline void Scan(int &x)
9 {
10 char c;
11 while((c = getchar()) < '0' || c > '9');
12 x = c - '0';
13 while((c = getchar()) >= '0' && c <= '9')
14 x = x * 10 + c - '0';
15 }
16 const int maxn = 1233;
17 const int maxq = 300233;
18 struct dot
19 {
20 int x, y, v;
21 };
22 dot c[maxq];
23 struct ask
24 {
25 int x, y, a, b, c;
26 };
27 ask a[maxq];
28 int n, q;
29 int p;
30 int num;
31 int ans[maxq];
32 int id[maxq], tmp[maxq];
33 bool lr[maxq];
34 int tr[maxn][maxn];
35 inline void Ins(int x, int y, int z)
36 {
37 for(int i = x; i <= n; i += i & -i)
38 for(int j = y; j <= n; j += j & -j)
39 tr[i][j] += z;
40 }
41 inline int Ask(int x, int y)
42 {
43 int sum = 0;
44 for(int i = x; i; i -= i & -i)
45 for(int j = y; j; j -= j & -j)
46 sum += tr[i][j];
47 return sum;
48 }
49 inline void Two(int x, int y, int l, int r)
50 {
51 if(x > y) return;
52 if(l == r)
53 {
54 for(int i = x; i <= y; ++i) ans[id[i]] = r;
55 return;
56 }
57 int mi = l + r >> 1;
58 while(c[p + 1].v <= mi) ++p, Ins(c[p].x, c[p].y, 1);
59 while(c[p].v > mi) Ins(c[p].x, c[p].y, -1), --p;
60 int tot, cnt = 0;
61 for(int i = x; i <= y; ++i)
62 {
63 int k = id[i];
64 tot = Ask(a[k].a, a[k].b) - Ask(a[k].a, a[k].y - 1) - Ask(a[k].x - 1, a[k].b) + Ask(a[k].x - 1, a[k].y - 1);
65 if(tot >= a[k].c) lr[i] = true, ++cnt;
66 else lr[i] = false;
67 }
68 int le = x - 1, ri = x + cnt - 1;
69 for(int i = x; i <= y; ++i)
70 if(lr[i]) tmp[++le] = id[i];
71 else tmp[++ri] = id[i];
72 for(int i = x; i <= y; ++i) id[i] = tmp[i];
73 Two(x, le, l, mi), Two(le + 1, ri, mi + 1, r);
74 }
75 inline bool rule(dot a, dot b)
76 {
77 return a.v < b.v;
78 }
79 int main()
80 {
81 Scan(n), Scan(q);
82 int val;
83 for(int i = 1; i <= n; ++i)
84 for(int j = 1; j <= n; ++j)
85 {
86 Scan(val);
87 c[++num] = (dot) {i, j, val};
88 }
89 sort(c + 1, c + 1 + num, rule);
90 for(int i = 1; i <= q; ++i)
91 Scan(a[i].x), Scan(a[i].y), Scan(a[i].a), Scan(a[i].b), Scan(a[i].c), id[i] = i;
92 Two(1, q, 0, c[num].v);
93 for(int i = 1; i <= q; ++i) printf("%d\n", ans[i]);
94 }