您的位置:首页 > 其它

bzoj 2738 矩阵乘法

2017-06-13 17:10 344 查看
2738: 矩阵乘法

Time Limit: 20 Sec Memory Limit: 256 MB

Submit: 1529 Solved: 660

[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。

Source

【分析】

题目与题干完全没有关系系列。

整体二分。

首先把整个矩阵哈希排序,然后做整体二分。

设当前答案为mid,那么将哈希排好序的矩阵中所有val < mid的数字加入bit中,对于每个询问拆成四个容斥一发,统计出来询问范围内 < mid的数字有多少个,即为cnt。如果k > cnt,把询问划分到[mid,r],否则划分到[l,mid-1]。

注意bit的添加与删除设立一个指针now来完成,否则暴力加入删除会TLE。

【代码】

//bzoj 2738 矩阵乘法
#include<bits/stdc++.h>
#define ll long long
#define p(i,j) ((i-1)*n+(j))
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=505;
int n,Q,mx,now;
int c[mxn][mxn],ans[60005];
struct node {int x,y,val;} a[250005];
struct query {int id,x1,y1,x2,y2,k;} q[60005],tmp[60005];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
inline bool comp(node u,node v)
{
return u.val<v.val;
}
inline int lowbit(int x) {return x&-x;}
inline void add(int x,int y,int v)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=n;j+=lowbit(j))
c[i][j]+=v;
}
inline int getsum(int x,int y)
{
int sum=0;
for(int i=x;i>=1;i-=lowbit(i))
for(int j=y;j>=1;j-=lowbit(j))
sum+=c[i][j];
return sum;
}
inline void CDQ(int L,int R,int l,int r)
{
int i,j,l1=L,l2=R,mid=(l+r>>1)+1;
if(L>R) return;
if(l==r)
{
fo(i,L,R) ans[q[i].id]=l;
return;
}
while(now<n*n && a[now].val<mid)
++now,add(a[now].x,a[now].y,1);
while(now && a[now].val>=mid)
add(a[now].x,a[now].y,-1),--now;
fo(i,L,R)
{
int cnt=getsum(q[i].x2,q[i].y2)-getsum(q[i].x2,q[i].y1-1);
cnt=cnt-getsum(q[i].x1-1,q[i].y2)+getsum(q[i].x1-1,q[i].y1-1);
if(q[i].k>cnt) tmp[l2--]=q[i];
else tmp[l1++]=q[i];
}
reverse(tmp+l2+1,tmp+R+1);
fo(i,L,R) q[i]=tmp[i];
CDQ(l2+1,R,mid,r),CDQ(L,l1-1,l,mid-1);
}
int main()
{
//  freopen("rand.txt","r",stdin);
int i,j;
n=read(),Q=read();
fo(i,1,n)
fo(j,1,n)
a[p(i,j)]=(node){i,j,read()};
fo(i,1,Q)
{
q[i].x1=read(),q[i].y1=read();
q[i].x2=read(),q[i].y2=read();
q[i].k=read(),q[i].id=i;
}
sort(a+1,a+n*n+1,comp);
CDQ(1,Q,0,a[n*n].val);
fo(i,1,Q) printf("%d\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: