题目:
题意:
个鬼的矩阵乘法
给出整个矩阵每个格子的数值大小,对于多个询问我们需要求出其子矩阵中的第
k
k
k大
分析:
我们可以用整体二分的思路去解决此题,维护第 k k k大的话就用树状数组做前缀和维护
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>
#include<vector>
#define LL long long
using namespace std;
inline int read() {
int d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
struct tree{
int x1,y1,x2,y2,k,id;
}t[310005],t1[310005],t2[310005];
int ans[60005],s[505][505],n=read(),q=read(),cnt=0;
int lowbit(int k) {return k&(-k);}
void add(int x,int y,int w)
{
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=n;j+=lowbit(j))
s[i][j]+=w;
return;
}
int gg(int x,int y)
{
if(!x||!y) return 0;
int sum=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))
sum+=s[i][j];
return sum;
}
int get(int x1,int y1,int x2,int y2)
{
return gg(x2,y2)-gg(x1-1,y2)-gg(x2,y1-1)+gg(x1-1,y1-1);
}
void ef(int l,int r,int L,int R)
{
if(L>R) return;
if(l==r)
{
for(int i=L;i<=R;i++) if(t[i].id) ans[t[i].id]=l;
return;
}
int mid=(l+r)>>1;
int cnt1=0,cnt2=0;
for(int i=L;i<=R;i++)
{
if(!t[i].id)
{
if(t[i].k<=mid) add(t[i].x1,t[i].y1,1),t1[++cnt1]=t[i];
else t2[++cnt2]=t[i];
}
else
{
int bc=get(t[i].x1,t[i].y1,t[i].x2,t[i].y2);
if(bc>=t[i].k) t1[++cnt1]=t[i];
else t[i].k-=bc,t2[++cnt2]=t[i];
}
}
for(int i=1;i<=cnt1;i++) if(!t1[i].id) add(t1[i].x1,t1[i].y1,-1);
for(int i=L;i<=L+cnt1-1;i++) t[i]=t1[i-L+1];
for(int i=L+cnt1;i<=R;i++) t[i]=t2[i-L-cnt1+1];
ef(l,mid,L,L+cnt1-1);ef(mid+1,r,L+cnt1,R);
return;
}
int main()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
t[++cnt]=(tree){i,j,0,0,read(),0};
for(int i=1;i<=q;i++)
t[++cnt]=(tree){read(),read(),read(),read(),read(),i};
ef(0,1000000000,1,cnt);
for(int i=1;i<=q;i++) printf("%d\n",ans[i]);
return 0;
}