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

题目:

我是超链接

题解:

又是一个整体二分了,因为本人的手残导致现在才调出来,具体来说就是
首先把权值离散
将所有的点看成是单个插入操作,所有的询问看成是查询操作
二分第k小的数mid,将插入操作按照权值排序了之后就是在一段区间里
将<=mid的数加入到bit里,然后对于每一个询问在bit中查询
如果不够的话就往大的走,如果小的话就往小的走
注意如果向mid,r走的话要将k减去当前的答案
要加快读卡常才能过Orz

代码:

#include <map>
#include <cstdio>
#include <algorithm>
using namespace std;
const int M=60005;
const int N=505;
const int pf=255025;
struct po{int x,y,val;}zb[pf];
struct hh{int x1,y1,x2,y2,id,k,num;}q[M];
int c[N][N],a[N][N],n,ans[M],s[pf];
map<int,int>hash;
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;
}
void add(int x,int y,int v)
{
    for (int i=x;i<=n;i+=i&(-i))
      for (int j=y;j<=n;j+=j&(-j)) c[i][j]+=v;
}
int qurry(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(hh a,hh b){return a.num<b.num;}
void ef(int l,int r,int a,int b,int x,int y)
{
    if (a>b) return;
    int mid=(l+r)>>1;
    if (l==r)
    {
        for (int i=a;i<=b;i++) ans[q[i].id]=l;
        return;
    }
    int pm=0;
    for (int i=x;i<=y;i++)
      if (zb[i].val<=mid) pm=i,add(zb[i].x,zb[i].y,1);
      else break;
    int pa=0,pb=b-a+1;
    for (int i=a;i<=b;i++)
    {
        int t=qurry(q[i].x2,q[i].y2)-qurry(q[i].x1-1,q[i].y2)-qurry(q[i].x2,q[i].y1-1)+qurry(q[i].x1-1,q[i].y1-1);
        if (t>=q[i].k) q[i].num=++pa;
        else q[i].num=++pb,q[i].k-=t;
    }
    for (int i=x;i<=pm;i++) add(zb[i].x,zb[i].y,-1);
    sort(q+a,q+b+1,cmp);
    ef(l,mid,a,a+pa-1,x,pm);
    ef(mid+1,r,a+pa,b,pm+1,y);
}
int cmp1(po a,po b){return a.val<b.val;}
int main()
{
    int Q;n=read();Q=read();int num=0;
    for (int i=1;i<=n;i++) 
      for (int j=1;j<=n;j++) a[i][j]=read(),s[++num]=a[i][j];
    sort(s+1,s+num+1);
    int ha=unique(s+1,s+num+1)-s-1;
    for (int i=1;i<=ha;i++) hash[s[i]]=i;
    num=0;
    for (int i=1;i<=n;i++)
      for (int j=1;j<=n;j++) zb[++num].val=hash[a[i][j]],zb[num].x=i,zb[num].y=j;
    for (int i=1;i<=Q;i++) q[i].x1=read(),q[i].y1=read(),q[i].x2=read(),q[i].y2=read(),q[i].k=read(),q[i].id=i;
    sort(zb+1,zb+num+1,cmp1);
    ef(1,ha,1,Q,1,num);
    for (int i=1;i<=Q;i++) printf("%d\n",s[ans[i]]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值