传送门
首先我们知道,这题数据有两部分:
对于50%的数据,满足R, C≤200,M≤200,000;
另有50%的数据,满足R=1,C≤500,000,M≤20,000;
对于前50%的数据,我们可以直接二分取书的页数下界解决。
于是我们定义to[i][j][k]表示矩阵[1,1]至矩阵[i,j]中所有不小于k的数的总和,num[i][j][k]为它们的个数。
于是从[a,b]到[c,d]中不小于k的数的和为
to[c][d][k]-to[a-1][d][k]-to[c][b-1][k]+to[a-1][b-1][k]
个数为
num[c][d][k]-num[a-1][d][k]-num[c][b-1][k]+num[a-1][b-1][k]
最后由于可能有重复的书页数,于是在最后减去多余的。
对于后50%的数据,我们用主席树维护一下子树的和与数量,跑一遍主席树然后去重。
Code:
#include
#include
#include
#define mid (l+r)/2
using namespace std;
int tot[6000010],lc[6000010],rc[6000010],sum[6000010],rt[500010];
int to[210][210][1010],num[210][201][1010];
int n,m,q,len(0),v,d;
void update(int x,int &now,int l,int r)
{
if(!now) now=++len;
tot[now]=tot[x]+v;
sum[now]=sum[x]+d;
if(l==r) return;
if(v<=mid)
{
rc[now]=rc[x];
update(lc[x],lc[now],l,mid);
}
else
{
lc[now]=lc[x];
update(rc[x],rc[now],mid+1,r);
}
}
int solve(int x,int y,int h)
{
int begin=h;
int xx=rt[x-1],yy=rt[y];
if(tot[yy]-tot[xx]return 0;
int l=1,r=1000,total=0,t=0;
while(lint c=tot[rc[yy]]-tot[rc[xx]];
if(h<=c)
{
xx=rc[xx];yy=rc[yy];
l=mid+1;
}
else
{
h-=c;
t+=sum[rc[yy]]-sum[rc[xx]];
total+=c;
xx=lc[xx];yy=lc[yy];
r=mid;
}
}
return t+ceil((double)(begin-total)/l);
}
void work1()
{
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
v=x;d=1;
update(rt[i-1],rt[i],1,1000);
}
for(int i=1;i<=q;i++)
{
int a,b,c,d,h;
scanf("%d %d %d %d %d",&a,&b,&c,&d,&h);
int p=solve(b,d,h);
if(p) printf("%d\n",p);
else printf("Poor QLW\n");
}
}
int check(int a,int b,int c,int d,int k)
{
return to[c][d][k]-to[a-1][d][k]-to[c][b-1][k]+to[a-1][b-1][k];
}
int get_sum(int a,int b,int c,int d,int k)
{
return num[c][d][k]-num[a-1][d][k]-num[c][b-1][k]+num[a-1][b-1][k];
}
void work2()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
int x;
scanf("%d",&x);
for(int k=1;k<=1000;k++)
{
to[i][j][k]=to[i-1][j][k]+to[i][j-1][k]-to[i-1][j-1][k]+(x>=k?x:0);
num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+(x>=k?1:0);
}
}
}
for(int i=1;i<=q;i++)
{
int a,b,c,d,h;
scanf("%d %d %d %d %d",&a,&b,&c,&d,&h);
int l=1,r=1000,ans=-1;
while(l<=r)
{
if(check(a,b,c,d,mid)>=h) ans=mid,l=mid+1;
else r=mid-1;
}
if(ans==-1) printf("Poor QLW\n");
else printf("%d\n",get_sum(a,b,c,d,ans)-(check(a,b,c,d,ans)-h)/ans);
}
}
int main()
{
scanf("%d %d %d",&n,&m,&q);
if(n==1) work1();
else work2();
}