码迷,mamicode.com
首页 > 编程语言 > 详细

[BZOJ2738]矩阵乘法 整体二分+二维树状数组

时间:2017-10-25 15:29:02      阅读:226      评论:0      收藏:0      [点我收藏+]

标签:++   algo   scanf   nbsp   一起   i++   www.   line   problems   

2738: 矩阵乘法

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 1643  Solved: 715
[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

 

  矩阵中数字是109以内的非负整数;

  20%的数据:N<=100,Q<=1000;

  40%的数据:N<=300,Q<=10000;

  60%的数据:N<=400,Q<=30000;

  100%的数据:N<=500,Q<=60000。

 

先将矩阵中所有元素排序,然后对于所有询问一起二分

 

技术分享
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<algorithm>
 7 using namespace std;
 8 int n,q;
 9 struct tmp {
10     int v,x,y;
11     bool operator <(const tmp &t)const {
12         return v<t.v;
13     }
14 }a[250005];
15 int cnt=0;
16 struct data {
17     int x1,y1,x2,y2,k,id,ans;
18 }ask[60006],s[60005];
19 int sum[505][505];
20 int lowbit(int x){return x&(-x);}
21 void update(int x,int y,int add) {
22     for(int i=x;i<=n;i+=lowbit(i))
23         for(int j=y;j<=n;j+=lowbit(j)) sum[i][j]+=add;
24 }
25 int query(int x,int y) {
26     int an=0;
27     for(int i=x;i>0;i-=lowbit(i))
28         for(int j=y;j>0;j-=lowbit(j)) an+=sum[i][j];
29     return an;
30 }
31 int get(int x1,int y1,int x2,int y2) {
32     return query(x2,y2)+query(x1-1,y1-1)-query(x1-1,y2)-query(x2,y1-1);
33 }
34 void solve(int l,int r,int ql,int qr) {
35     if(ql>qr) return;
36     if(l==r) {
37         for(int i=ql;i<=qr;i++) ask[i].ans=a[l].v;
38         return ;
39     }
40     int mid=(l+r)>>1;
41     for(int i=l;i<=mid;i++) update(a[i].x,a[i].y,1);
42     int head=ql-1,tail=0;
43     for(int i=ql;i<=qr;i++) {
44         int nowk=get(ask[i].x1,ask[i].y1,ask[i].x2,ask[i].y2);
45         if(nowk>=ask[i].k) ask[++head]=ask[i];
46         else {s[++tail]=ask[i];s[tail].k-=nowk;}
47     }
48     for(int i=1;i<=tail;i++) ask[++head]=s[i];
49     for(int i=l;i<=mid;i++) update(a[i].x,a[i].y,-1);
50     solve(l,mid,ql,qr-tail);
51     solve(mid+1,r,qr-tail+1,qr);
52     return ;
53 }
54 bool cmp(data t1,data t2) {
55     return t1.id<t2.id;
56 }
57 int main() {
58     scanf("%d%d",&n,&q);
59     for(int i=1;i<=n;i++)
60         for(int j=1;j<=n;j++){scanf("%d",&a[++cnt].v);a[cnt].x=i;a[cnt].y=j;}
61     sort(a+1,a+cnt+1);
62     for(int i=1;i<=q;i++) {
63         scanf("%d%d%d%d%d",&ask[i].x1,&ask[i].y1,&ask[i].x2,&ask[i].y2,&ask[i].k);
64         ask[i].id=i;
65     }
66     solve(1,cnt,1,q);
67     sort(ask+1,ask+1+q,cmp);
68     for(int i=1;i<=q;i++) printf("%d\n",ask[i].ans);
69 }
View Code

 

[BZOJ2738]矩阵乘法 整体二分+二维树状数组

标签:++   algo   scanf   nbsp   一起   i++   www.   line   problems   

原文地址:http://www.cnblogs.com/wls001/p/7728681.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!