【BZOJ】【2738】&【Tsinsen】【A1333】矩阵乘法
整体二分+树状数组
过了【BZOJ】【2527】【POI2011】Meteors以后这题就没那么难啦~
关键是【从小到大】依次插入数字,然后整体二分每个查询的第k大是在第几次插入中被插入的……嗯大概就是这样
1 /************************************************************** 2 Problem: 2738 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:11852 ms 7 Memory:7216 kb 8 ****************************************************************/ 9 10 //BZOJ 2738 11 #include<cstdio> 12 #include<cstring> 13 #include<cstdlib> 14 #include<iostream> 15 #include<algorithm> 16 #define rep(i,n) for(int i=0;i<n;++i) 17 #define F(i,j,n) for(int i=j;i<=n;++i) 18 #define D(i,j,n) for(int i=j;i>=n;--i) 19 #define pb push_back 20 using namespace std; 21 typedef long long LL; 22 inline int getint(){ 23 int r=1,v=0; char ch=getchar(); 24 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 25 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 26 return r*v; 27 } 28 const int N=510,M=60010; 29 /*******************template********************/ 30 31 int n,m; 32 struct node{ 33 int v,x,y; 34 }a[N*N]; 35 bool cmp(node a,node b){return a.v<b.v;} 36 struct ques{ 37 int x1,y1,x2,y2,k; 38 void read(){x1=getint(); y1=getint(); x2=getint(); y2=getint(); k=getint();} 39 }Q[M]; 40 41 int c[N][N]; 42 int t[M],q[M],ans[M]; 43 44 void add(int x,int y,int v){ 45 for(int i=x;i<=n;i+=i&(-i)) 46 for(int j=y;j<=n;j+=j&(-j)) c[i][j]+=v; 47 } 48 int sum(int x,int y){ 49 int r=0; 50 for(int i=x;i;i-=i&(-i)) 51 for(int j=y;j;j-=j&(-j)) r+=c[i][j]; 52 return r; 53 } 54 int sum(int x1,int y1,int x2,int y2){ 55 x1--; y1--; 56 return sum(x2,y2)-sum(x1,y2)-sum(x2,y1)+sum(x1,y1); 57 } 58 void solve(int ql,int qr,int l,int r){ 59 // printf("solve %d %d %d %d",ql,qr,l,r); cout <<endl; 60 if (ql>qr) return; 61 if (l==r){ 62 F(i,ql,qr) ans[t[i]]=a[l].v; 63 return; 64 } 65 int t1=ql-1,t2=qr+1,mid=l+r>>1; 66 F(i,l,mid) add(a[i].x,a[i].y,1); 67 F(i,ql,qr){ 68 int x1=Q[t[i]].x1,y1=Q[t[i]].y1,x2=Q[t[i]].x2,y2=Q[t[i]].y2,k=Q[t[i]].k; 69 int num=sum(x1,y1,x2,y2); 70 // printf("%d %d %d %d num=%d\n",x1,y1,x2,y2,num); 71 if (num>=k) q[++t1]=t[i]; 72 else Q[t[i]].k-=num,q[--t2]=t[i]; 73 } 74 F(i,ql,qr) t[i]=q[i]; 75 F(i,l,mid) add(a[i].x,a[i].y,-1); 76 solve(ql,t1,l,mid); solve(t2,qr,mid+1,r); 77 } 78 79 int main(){ 80 #ifndef ONLINE_JUDGE 81 freopen("2738.in","r",stdin); 82 freopen("2738.out","w",stdout); 83 #endif 84 n=getint(); m=getint(); 85 F(i,1,n) F(j,1,n){ 86 int t=(i-1)*n+j; 87 a[t].v=getint(); 88 a[t].x=i; a[t].y=j; 89 } 90 sort(a+1,a+n*n+1,cmp); 91 F(i,1,m) Q[i].read(),t[i]=i; 92 93 solve(1,m,1,n*n); 94 F(i,1,m) printf("%d\n",ans[i]); 95 return 0; 96 }
2738: 矩阵乘法
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 859 Solved: 364
[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小数。
接下来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
2 1
3 4
1 2 1 2 1
1 1 2 2 3
Sample Output
1
3
3
HINT
矩阵中数字是109以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。