1. 程式人生 > >BZOJ 2738 矩陣乘法 (整體二分+二維樹狀數組)

BZOJ 2738 矩陣乘法 (整體二分+二維樹狀數組)

sort ret 分答 truct show tmp 二分答案 += all

題目大意:略

洛谷傳送門

多次詢問第k小,考慮整體二分

考慮二分答案,為了避免同一權值的數出現在不同位置的情況,用一個$vector$存儲權值為i的點在那些位置。而權值可能會很大,我們將其離散。

每次選擇一個答案$mid$,把矩陣中權值為$[l,mid]$的點加入到二維樹狀數組中,即可在$O(log^{2}n)$時間內,快速求出子矩陣內權值是$[l,mid]$的點的數量

如果這個數量小於某個詢問的$k$,說明第$k$大的數一定大於$mid$,把它加入右區間遞歸

否則說明第$k$大的數小於等於$mid$,加入左區間遞歸

總時間$O((Q+n^{2})log^{3}n)$但樹狀數組常數小跑不滿

 1 #include <vector>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define N1 505
 6 #define M1 60500
 7 #define ll long long
 8 #define dd double
 9 #define inf 233333333
10 using namespace std;
11 
12 int gint()
13 {
14     int ret=0,fh=1;char
c=getchar(); 15 while(c<0||c>9){if(c==-)fh=-1;c=getchar();} 16 while(c>=0&&c<=9){ret=ret*10+c-0;c=getchar();} 17 return ret*fh; 18 } 19 int n,m,nn,Q,K; 20 struct BIT{ 21 int sum[N1][N1]; 22 void update(int x,int y,int w) 23 { 24 for(int i=x;i<=n;i+=(i&(-i)))
25 for(int j=y;j<=n;j+=(j&(-j))) 26 sum[i][j]+=w; 27 } 28 int query(int x,int y) 29 { 30 int ans=0; 31 for(int i=x;i;i-=(i&(-i))) 32 for(int j=y;j;j-=(j&(-j))) 33 ans+=sum[i][j]; 34 return ans; 35 } 36 void clr(int x,int y) 37 { 38 for(int i=x;i<=n;i+=(i&(-i))) 39 for(int j=y;j<=n;j+=(j&(-j))) 40 sum[i][j]=0; 41 } 42 }s; 43 struct node{int x,y;}a[N1*N1]; 44 struct Query{int xa,ya,xb,yb,K,t;}q[M1],tmp[M1]; 45 int f[M1],mp[N1][N1],w[N1*N1],ma; 46 vector<node>pos[N1*N1]; 47 48 void alldic(int l,int r,int ql,int qr) 49 { 50 if(l>r||ql>qr) return; 51 int mid=(l+r)>>1,i,j,S=ql,E=qr,ans; 52 for(i=l;i<=mid;i++) for(j=0;j<pos[i].size();j++) 53 s.update(pos[i][j].x,pos[i][j].y,1); 54 for(i=ql;i<=qr;i++) 55 { 56 ans=s.query(q[i].xb,q[i].yb)+s.query(q[i].xa,q[i].ya)-s.query(q[i].xb,q[i].ya)-s.query(q[i].xa,q[i].yb); 57 if(ans<q[i].K){ q[i].K-=ans; tmp[E--]=q[i]; } 58 else{ tmp[S++]=q[i]; f[q[i].t]=w[mid]; } 59 } 60 for(i=ql;i<=qr;i++) q[i]=tmp[i]; 61 for(i=l;i<=mid;i++) for(j=0;j<pos[i].size();j++) 62 s.clr(pos[i][j].x,pos[i][j].y); 63 alldic(l,mid-1,ql,S-1); alldic(mid+1,r,E+1,qr); 64 } 65 66 67 int main() 68 { 69 scanf("%d%d",&n,&Q); 70 int i,j; nn=n*n; 71 for(i=1,nn=0;i<=n;i++) for(j=1;j<=n;j++) mp[i][j]=gint(),w[++nn]=mp[i][j]; 72 sort(w+1,w+nn+1); ma=unique(w+1,w+nn+1)-(w+1); 73 for(i=1;i<=n;i++) for(j=1;j<=n;j++) 74 { mp[i][j]=lower_bound(w+1,w+ma+1,mp[i][j])-w; pos[mp[i][j]].push_back((node){i,j}); } 75 for(i=1;i<=Q;i++) 76 { q[i].xa=gint()-1; q[i].ya=gint()-1; q[i].xb=gint(); q[i].yb=gint(); q[i].K=gint(); q[i].t=i; } 77 alldic(1,ma,1,Q); 78 for(i=1;i<=Q;i++) printf("%d\n",f[i]); 79 return 0; 80 }

BZOJ 2738 矩陣乘法 (整體二分+二維樹狀數組)