[BZOJ2738]矩阵乘法-[整体二分+树状数组]

Description

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

(N<=500,Q<=60000)

Solution

考虑二分答案,问题转化为求矩阵内为1的点数,可以用二维树状数组。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
struct P{int num,x,y;}a[250010];int cnt_a=0;
bool cmp(P x,P y){return x.num<y.num;}
int rk[100100],all=0;

int n,m;
struct node{int x,y,xx,yy,k,id;
}q[60010],st[2][60010];int ans[60010];

int tree[510][510];
void add(int x,int y,int data){for(;x<=n;x+=x&-x)for(int j=y;j<=n;j+=j&-j) tree[x][j]+=data;}
int query(int x,int y){int re=0;for(;x;x-=x&-x)for(int j=y;j;j-=j&-j) re+=tree[x][j];return re;}
int now;
void solve(int ql,int qr,int ansl,int ansr)
{
    if (ql>qr) return;
    if (ansl==ansr) 
    {
        for (int i=ql;i<=qr;i++) ans[q[i].id]=ansl;
        return;
    }
    int ansmid=ansl+ansr>>1,cnt,js0=0,js1=0;
    for (;now<ansmid;) now++,add(a[now].x,a[now].y,1);
    for(;now>ansmid;now--) add(a[now].x,a[now].y,-1);
    for (int i=ql;i<=qr;i++)
    {
        cnt=query(q[i].xx,q[i].yy)+query(q[i].x-1,q[i].y-1)-query(q[i].x-1,q[i].yy)-query(q[i].xx,q[i].y-1);
        if (cnt>=q[i].k) st[0][++js0]=q[i];
        else st[1][++js1]=q[i];
    }
    for (int i=1;i<=js0;i++) q[i+ql-1]=st[0][i];
    for (int i=1;i<=js1;i++) q[i+ql+js0-1]=st[1][i];
    solve(ql,ql+js0-1,ansl,ansmid);
    solve(ql+js0,qr,ansmid+1,ansr);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) for (int j=1;j<=n;j++)
    {
        scanf("%d",&a[++cnt_a].num);a[cnt_a].x=i;a[cnt_a].y=j;
    }
    sort(a+1,a+cnt_a+1,cmp);
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d%d",&q[i].x,&q[i].y,&q[i].xx,&q[i].yy,&q[i].k);q[i].id=i;
    }
    solve(1,m,0,n*n);
    for (int i=1;i<=m;i++) printf("%d\n",a[ans[i]].num);
    
}

 

 

posted @ 2018-08-17 21:17  _雨后阳光  阅读(142)  评论(0编辑  收藏  举报