bzoj 2738 矩陣乘法
阿新 • • 發佈:2019-01-04
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;
}