1. 程式人生 > >bzoj 2738 矩陣乘法

bzoj 2738 矩陣乘法

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; }