洛谷1527 [国家集训队]矩阵乘法 Accepted(整体二分)(树状数组)

版权声明:本文为博主原创文章,未经博主允许不得转载,除非先点了赞。 https://blog.csdn.net/A_Bright_CH/article/details/83443334

题目

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

题解

整体二分+树状数组
求第k小的数我怎么就没想到整体二分呢!
还是挺裸的,把所有元素记录下位置一并放入中b队列中,询问也是。
因为是二维的,所以树状数组也要升级成二维的,s[x][y]表示(1,1)-(x,y)这个矩阵中小于等于mid的数的个数,酱紫就可以判断一个询问要取到bl还是br了。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=510,MAXQ=60010;

inline int read()
{
    int re=0;char ch=getchar();
    while(ch<'0' || ch>'9') ch=getchar();
    while(ch>='0' && ch<='9') re=re*10+(ch^48),ch=getchar();
    return re;
}

int n,Q;

struct U{int x,y,c;}a[MAXN*MAXN];int len=0;
bool cmp(U u1,U u2){return u1.c<u2.c;}

struct O{int x1,y1,x2,y2,k,id;}b[MAXQ];

int s[MAXN][MAXN];
void add(int x,int y,int c)
{
    for(int i=x;i<=n;i+=i&-i)
        for(int j=y;j<=n;j+=j&-j) s[i][j]+=c;
}
int getsum(int x,int y)
{
    int re=0;
    for(int i=x;i>=1;i-=i&-i)
        for(int j=y;j>=1;j-=j&-j) re+=s[i][j];
    return re;
}
void change(int x,int y,int c)
{
    add(x,y,c);//一个改点求段的二维树状数组
    /*if(x-1 && y-1) add(x-1,y-1,c);
    if(x-1) add(x-1,y,-c);
    if(y-1) add(x,y-1,-c);*/
}
int query(int x1,int y1,int x2,int y2)
{
    return getsum(x2,y2)+getsum(x1-1,y1-1)-getsum(x1-1,y2)-getsum(x2,y1-1);
}

int ans[MAXQ];
O bl[MAXQ],br[MAXQ];
void solve(int l,int r,int ql,int qr)
{
    if(ql>qr) return ;
    if(l==r)
    {
        for(int i=ql;i<=qr;i++) ans[b[i].id]=a[l].c;
        return ;
    }
    
    int tl=0,tr=0;
    int mid=l+r>>1;
    for(int i=l;i<=mid;i++) change(a[i].x,a[i].y,1);
    for(int i=ql;i<=qr;i++)
    {
        int tk=query(b[i].x1,b[i].y1,b[i].x2,b[i].y2);
        if(b[i].k<=tk) bl[++tl]=b[i];
        else br[++tr]=b[i],br[tr].k-=tk;
    }
    
    for(int i=ql,j=1;j<=tl;i++,j++) b[i]=bl[j];
    for(int i=qr,j=tr;j>=1;i--,j--) b[i]=br[j];
    for(int i=l;i<=mid;i++) change(a[i].x,a[i].y,-1);//debug (;i<=r;)
    
    solve(l,mid,ql,ql+tl-1);solve(mid+1,r,ql+tl,qr);
}

int main()
{
    n=read();Q=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) a[++len]=(U){i,j,read()};
    sort(a+1,a+len+1,cmp);
    for(int i=1;i<=Q;i++) b[i].x1=read(),b[i].y1=read(),b[i].x2=read(),b[i].y2=read(),b[i].k=read(),b[i].id=i;
    solve(1,len,1,Q);
    for(int i=1;i<=Q;i++) printf("%d\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/A_Bright_CH/article/details/83443334