【BZOJ2738】矩阵乘法 [整体二分][树状数组]
矩阵乘法
Time Limit: 20 Sec Memory Limit: 256 MB[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小数。
接下来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
矩阵中数字是10^9以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
Solution
由于只有询问,我们可以方便地使用整体二分来求解。
先将原矩阵以序列形式存下来,然后按照权值排序,接着我们二分序列上的位置来查询,在[l,mid]这一段序列上的点+1,然后像静态查Kth那么判断即可。(用二维树状数组加入权值)。
Code
1 #include<iostream>
2 #include<string>
3 #include<algorithm>
4 #include<cstdio>
5 #include<cstring>
6 #include<cstdlib>
7 #include<cmath>
8 #include<vector>
9 using namespace std;
10
11 const int ONE = 505;
12 const int QUE = 60005;
13
14 int n,Q;
15 int tot;
16 int C[ONE][ONE];
17 int Ans[QUE];
18
19 struct point
20 {
21 int x,y,val;
22 }a[ONE*ONE];
23 bool cmp(const point &a,const point &b) {return a.val < b.val;}
24
25 struct power
26 {
27 int x1,y1,x2,y2;
28 int k;
29 int id;
30 }oper[QUE],qL[QUE],qR[QUE];
31
32 int get()
33 {
34 int res=1,Q=1; char c;
35 while( (c=getchar())<48 || c>57)
36 if(c=='-')Q=-1;
37 if(Q) res=c-48;
38 while((c=getchar())>=48 && c<=57)
39 res=res*10+c-48;
40 return res*Q;
41 }
42
43 namespace Bit
44 {
45 int lowbit(int x) {return x&-x;}
46
47 void Add(int x,int y,int z)
48 {
49 for(int i=x;i<=n;i+=lowbit(i))
50 for(int j=y;j<=n;j+=lowbit(j))
51 C[i][j] += z;
52 }
53
54 int Query(int x,int y)
55 {
56 int res = 0;
57 for(int i=x;i>=1;i-=lowbit(i))
58 for(int j=y;j>=1;j-=lowbit(j))
59 res += C[i][j];
60 return res;
61 }
62
63 int Getans(power a)
64 {
65 return Query(a.x2,a.y2) - Query(a.x1-1,a.y2) - Query(a.x2,a.y1-1) + Query(a.x1-1,a.y1-1);
66 }
67 }
68
69 void Solve(int l,int r,int L,int R)//位置 询问
70 {
71 if(L>R) return;
72 if(l==r)
73 {
74 for(int i=L;i<=R;i++)
75 Ans[oper[i].id] = a[l].val;
76 return;
77 }
78
79 int mid=(l+r)>>1;
80 for(int i=l;i<=mid;i++)
81 Bit::Add(a[i].x,a[i].y,1);
82
83 int l_num=0,r_num=0;
84 for(int i=L;i<=R;i++)
85 {
86 int record = Bit::Getans(oper[i]);
87 if(record >= oper[i].k)
88 qL[++l_num] = oper[i];
89 else
90 oper[i].k-=record, qR[++r_num] = oper[i];
91 }
92
93 for(int i=l;i<=mid;i++)
94 Bit::Add(a[i].x,a[i].y,-1);
95
96 int t=L;
97 for(int i=1;i<=l_num;i++) oper[t++] = qL[i];
98 for(int i=1;i<=r_num;i++) oper[t++] = qR[i];
99
100 Solve(l,mid,L,L+l_num-1);
101 Solve(mid+1,r,L+l_num,R);
102 }
103
104
105 int main()
106 {
107 n=get(); Q=get();
108 for(int i=1;i<=n;i++)
109 for(int j=1;j<=n;j++)
110 {
111 a[++tot].val = get();
112 a[tot].x = i; a[tot].y = j;
113 }
114 sort(a+1,a+tot+1,cmp);
115
116 for(int i=1;i<=Q;i++)
117 {
118 oper[i].x1=get(); oper[i].y1=get(); oper[i].x2=get(); oper[i].y2=get();
119 oper[i].k=get(); oper[i].id=i;
120 }
121
122 Solve(1,tot,1,Q);
123
124 for(int i=1;i<=Q;i++)
125 printf("%d\n",Ans[i]);
126 }