BZOJ 2738 矩阵乘法(整体二分+二维树状数组)

 

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=2738

 

【题目大意】

  给出一个方格图,询问要求求出矩阵内第k小的元素

 

【题解】

  我们对答案的大小进行整体二分,用二维树状数组维护二维区间和,
  将超过数量的分治到左区间,不满足的分治到右区间即可。

 

【代码】

#include <cstdio>
#include <algorithm>
#include <cstring> 
using namespace std;
const int N=250010,M=510;
namespace Td_BIT{
    int c[M][M];
    void Initialize(){memset(c,0,sizeof(c));}
    void add(int x,int y,int val){
        for(int i=x;i<M;i+=i&-i)
            for(int j=y;j<M;j+=j&-j)c[i][j]+=val;
    }
    int query(int x,int y){
        int res=0;
        for(int i=x;i;i-=i&-i)
            for(int j=y;j;j-=j&-j)res+=c[i][j];
        return res;
    }
}
struct Q{int x1,x2,y1,y2,k;}q[N];
struct data{int x,y,val;}a[N];
bool operator<(data a,data b){return a.val<b.val;}
int cnt;
int query(int k){
    using namespace Td_BIT;
    int x1=q[k].x1,y1=q[k].y1,x2=q[k].x2,y2=q[k].y2;
    return query(x2,y2)+query(x1-1,y1-1)-query(x1-1,y2)-query(x2,y1-1);
}
int mark[N],ans[N],id[N],tmp[N],T=0;
void solve(int l,int r,int L,int R){
    if(l>r||L==R)return;
    int mid=(L+R)>>1;
    while(a[T+1].val<=mid&&T<cnt){Td_BIT::add(a[T+1].x,a[T+1].y,1);T++;}
    while(a[T].val>mid){Td_BIT::add(a[T].x,a[T].y,-1);T--;}
    int cnt=0;
    for(int i=l;i<=r;i++){
        if(query(id[i])>q[id[i]].k-1){
            mark[i]=1;
            ans[id[i]]=mid;
            cnt++;
        }else mark[i]=0;
    }int l1=l,l2=l+cnt;
    for(int i=l;i<=r;i++){
        if(mark[i])tmp[l1++]=id[i];
        else tmp[l2++]=id[i];
    }for(int i=l;i<=r;i++)id[i]=tmp[i];
    solve(l,l1-1,L,mid);solve(l1,l2-1,mid+1,R);
}
int n,m;
int main(){
    scanf("%d%d",&n,&m);
    int mx=cnt=0;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            a[++cnt].x=i; a[cnt].y=j; 
            scanf("%d",&a[cnt].val);
            mx=max(a[cnt].val,mx);
        }
    }sort(a+1,a+cnt+1);
    for(int i=1;i<=m;i++)scanf("%d%d%d%d%d",&q[i].x1,&q[i].y1,&q[i].x2,&q[i].y2,&q[i].k);
    for(int i=1;i<=m;i++)id[i]=i;
    solve(1,m,0,mx+1);
    for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
    return 0;
}
posted @ 2017-07-19 20:29  forever97  阅读(220)  评论(0编辑  收藏  举报