BZOJ2738: 矩阵乘法

Description

  给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。

Input

 

  第一行两个数N,Q,表示矩阵大小和询问组数;
  接下来NN列一共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\n",ans[i]);
    return 0;
}
View Code

 

posted @ 2016-03-03 16:47  wzj_is_a_juruo  阅读(208)  评论(0编辑  收藏  举报