BZOJ 2738 矩陣乘法 (整體二分+二維樹狀數組)
阿新 • • 發佈:2019-01-03
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;charc=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 矩陣乘法 (整體二分+二維樹狀數組)