BZOJ2738 矩阵乘法

@zryabc  July 23, 2019

题目

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

思路

整体二分。

整体二分主要适用于对于二分状态的改变,可以在可接受的复杂度内修改的题目。

就本题而言,二分答案,如果考虑将[1,mid]的区间内的点加入树状数组中,在二维平面上标记为1,然后比较每个询问与K的关系,接着将询问分组,接着二分。

以上应该是整体二分的基本模型。

代码

#include<bits/stdc++.h>
#define M 60005
using namespace std;
struct node{
    int x,y,val;
    bool operator < (const node& res)const{
        return val<res.val;
    }
}B[505*505];
int n,Q,A[505][505],bcnt,ans[M],t1[M],t2[M];
int id[M],now;
struct que{
    int x1,y1,x2,y2,k;
}wk[M];
struct BIT{
    int C[505][505];
    void Add(int x,int y,int d){
        x++;y++;
        while(x<=n+1){
            int a=y;
            while(y<=n+1){
                C[x][y]+=d;
                y+=(y&-y);
            }   
            y=a;
            x+=(x&-x);
        }
    }
    int sum(int x,int y){
        x++;y++;
        int res=0;
        while(x){
            int a=y;
            while(y){
                res+=C[x][y];
                y-=(y&-y);
            }
            y=a;
            x-=(x&-x);
        }
        return res;
    }
}T;
void update(int x,int f){
    T.Add(B[x].x,B[x].y,f); 
}
int query(int x1,int y1,int x2,int y2){
    return T.sum(x2,y2)-T.sum(x1-1,y2)-T.sum(x2,y1-1)+T.sum(x1-1,y1-1); 
}
void solve(int l,int r,int ql,int qr){
    if(l>r)return;
    if(ql==qr){
        for(int i=l;i<=r;i++)ans[id[i]]=ql;
        return;
    }
    int mid=(ql+qr)>>1,c1=0,c2=0,c=l-1;
    while(now<mid)update(++now,1);
    while(now>mid)update(now--,-1);
    for(int i=l;i<=r;i++){
        if(query(wk[id[i]].x1,wk[id[i]].y1,wk[id[i]].x2,wk[id[i]].y2)<wk[id[i]].k)t1[++c1]=id[i];
        else t2[++c2]=id[i];
    }
    for(int i=1;i<=c2;i++)id[++c]=t2[i];
    for(int i=1;i<=c1;i++)id[++c]=t1[i];
    solve(l,l+c2-1,ql,mid);solve(l+c2,r,mid+1,qr);
}
int main(){
//  freopen("1.in","r",stdin);
//  freopen("1.ans","w",stdout);
    scanf("%d%d",&n,&Q);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&A[i][j]),B[++bcnt].val=A[i][j],B[bcnt].x=i,B[bcnt].y=j;
    sort(B+1,B+bcnt+1);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            int l=1,r=bcnt,res=-1;
            while(l<=r){
                int mid=(l+r)>>1;
                if(B[mid].val>=A[i][j]){
                    res=mid;
                    r=mid-1;
                }
                else l=mid+1;
            }
            A[i][j]=res;
        }
    for(int i=1;i<=Q;i++){
        scanf("%d%d%d%d%d",&wk[i].x1,&wk[i].y1,&wk[i].x2,&wk[i].y2,&wk[i].k);
        id[i]=i;
    }
    solve(1,Q,1,bcnt);
    for(int i=1;i<=Q;i++){
        printf("%d\n",B[ans[i]].val);
    }
    return 0;
}

添加新评论