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
矩阵中数字是10^9以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
我们可以整体二分,这样可以转换成对于每个矩形计算其内部有多少点。
扫描线+树状数组就可以了,时间复杂度O(Nlog^2N)。
#include<cstdio> #include<cctype> #include<queue> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c=='-') f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-'0'; return x*f; } const int maxn=250010; const int maxm=60010; const int maxc=510; struct Array { int x,y,val; bool operator < (const Array& ths) const {return val<ths.val;} }A[maxn]; struct Query { int x,y,l,r,k,id; }q[maxm]; int n,m,r,Q[maxm],tmp[maxm],ans[maxm]; struct Point { int x,y; bool operator < (const Point& ths) const {return x<ths.x;} }P[maxn]; int res[maxm]; struct Rect { int x,l,r,tp,id; bool operator < (const Rect& ths) const {return x<ths.x;} }B[maxm<<1]; int sumv[maxc],cur[maxc],clo; int query(int x) { int res=0; for(;x;x-=x&-x) if(cur[x]==clo) res+=sumv[x]; return res; } void add(int x,int v) { for(;x<=r;x+=x&-x) if(cur[x]==clo) sumv[x]+=v; else cur[x]=clo,sumv[x]=v; } void solve(int l,int r,int h,int t) { if(h>t) return; if(l==r) { rep(i,h,t) ans[q[Q[i]].id]=A[l].val; return; } int mid=l+r>>1,m1=0,m2=0; rep(i,l,mid) P[++m1]=(Point){A[i].x,A[i].y}; rep(i,h,t) { res[i]=0; B[++m2]=(Rect){q[Q[i]].x-1,q[Q[i]].l,q[Q[i]].r,-1,i}; B[++m2]=(Rect){q[Q[i]].y,q[Q[i]].l,q[Q[i]].r,1,i}; } sort(P+1,P+m1+1);sort(B+1,B+m2+1);int j=1;clo++; rep(i,1,m2) { while(j<=m1&&P[j].x<=B[i].x) add(P[j].y,1),j++; res[B[i].id]+=B[i].tp*(query(B[i].r)-query(B[i].l-1)); } int L=h,R=t; rep(i,h,t) if(res[i]>=q[Q[i]].k) tmp[L++]=Q[i]; else q[Q[i]].k-=res[i],tmp[R--]=Q[i]; rep(i,h,t) Q[i]=tmp[i];//开始手残没有写这行话QAQ(AQ)* solve(l,mid,h,R);solve(mid+1,r,R+1,t); } int main() { r=read();m=read(); rep(i,1,r) rep(j,1,r) A[++n]=(Array){i,j,read()}; sort(A+1,A+n+1); rep(i,1,m) q[Q[i]=q[i].id=i].x=read(),q[i].l=read(),q[i].y=read(),q[i].r=read(),q[i].k=read(); solve(1,n,1,m); rep(i,1,m) printf("%d ",ans[i]); return 0; }