[BZOJ2738]矩阵乘法(整体二分+二维bit)

33 篇文章 0 订阅

题目描述

传送门

题解

首先把权值离散
将所有的点看成是单个插入操作,所有的询问看成是查询操作
二分第k小的数mid,将插入操作按照权值排序了之后就是在一段区间里
将<=mid的数加入到bit里,然后对于每一个询问在bit中查询
如果不够的话就往大的走,如果小的话就往小的走
注意如果向mid,r走的话要将k减去当前的答案

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
#define N 505

int n,q,m,LSH;
int squ[N][N],lsh[N*N],ans[N*N];
struct hp{int x,y,p,q,k,val,id,num;}ins[N*N],que[N*N];
int C[N][N];

int read()
{
    int x=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
int find(int x)
{
    int l=1,r=LSH,mid,ans;
    while (l<=r)
    {
        mid=(l+r)>>1;
        if (lsh[mid]>=x) ans=mid,r=mid-1;
        else l=mid+1;
    }
    return ans;
}
void add(int x,int y,int val)
{
    for (int i=x;i<=n;i+=i&(-i))
        for (int j=y;j<=n;j+=j&(-j))
            C[i][j]+=val;
}
int query(int x,int y)
{
    int ans=0;
    for (int i=x;i>=1;i-=i&(-i))
        for (int j=y;j>=1;j-=j&(-j))
            ans+=C[i][j];
    return ans;
}
int cmp(hp a,hp b)
{
    return a.num<b.num;
}
void dvd(int l,int r,int x,int y,int a,int b)
{
    if (a>b) return;
    if (l==r)
    {
        for (int i=a;i<=b;++i)
            ans[que[i].id]=l;
        return;
    }
    int mid=(l+r)>>1;
    int pmid=0,pa=0,pb=b-a+1;
    for (int i=x;i<=y;++i)
        if (ins[i].val<=mid)
        {
            pmid=i;
            add(ins[i].x,ins[i].y,1);
        }
        else break;
    for (int i=a;i<=b;++i)
    {
        int t=t=query(que[i].x-1,que[i].y-1)+query(que[i].p,que[i].q)-query(que[i].x-1,que[i].q)-query(que[i].p,que[i].y-1);
        if (t<que[i].k) que[i].k-=t,que[i].num=++pb;
        else que[i].num=++pa;
    }
    for (int i=x;i<=pmid;++i)
        add(ins[i].x,ins[i].y,-1);
    sort(que+a,que+b+1,cmp);
    dvd(l,mid,x,pmid,a,a+pa-1);
    dvd(mid+1,r,pmid+1,y,a+pa,b);
}
int cmpval(hp a,hp b)
{
    return a.val<b.val;
}
int main()
{
    n=read();q=read();
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
        {
            squ[i][j]=read();
            lsh[++LSH]=squ[i][j];
        }
    sort(lsh+1,lsh+LSH+1);
    LSH=unique(lsh+1,lsh+LSH+1)-lsh-1;
    for (int i=1;i<=n;++i)
        for (int j=1;j<=n;++j)
        {
            squ[i][j]=find(squ[i][j]);
            ins[++m].x=i,ins[m].y=j,ins[m].val=squ[i][j];
        }
    for (int i=1;i<=q;++i)
    {
        que[i].x=read();que[i].y=read();que[i].p=read();que[i].q=read();que[i].k=read();
        que[i].id=i;
    }
    sort(ins+1,ins+m+1,cmpval);
    dvd(1,LSH,1,m,1,q);
    for (int i=1;i<=q;++i)
        printf("%d\n",lsh[ans[i]]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值