【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小数。

Output

  对于每组询问输出第K小的数。

Sample Input

  2 2
  2 1
  3 4
  1 2 1 2 1
  1 1 2 2 3

Sample Output

  1
  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 }
View Code

 

posted @ 2017-03-16 21:21  BearChild  阅读(393)  评论(0编辑  收藏  举报