1. 程式人生 > >[BZOJ2738]矩陣乘法 整體二分+二維樹狀數組

[BZOJ2738]矩陣乘法 整體二分+二維樹狀數組

所有 logs == display 乘法 pen bool time ask

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]矩陣乘法 整體二分+二維樹狀數組