题目描述:
给出 N * M 的 表格 每个位置有一个权值 K
给出 Q 个查询
每次查询限定一个矩形区域 问至少在本矩形区域内取出多少个元素才可以>=Qi
题目分析:
YY了半天没想出来
看了下数据范围就懂了!
对于50%的数据,满足R, C≤200,M≤200,000;
另有50%的数据,满足R=1,C≤500,000,M≤20,000;
很明显是要我们分情况写算法
前50%数据 由于范围较小 我们可以直接 开数组维护矩形前缀和
num[i][j][k]表示以i,j,为右上角的且元素>=k矩形前缀和
f[i][j][k]表示以i,j为右上角的且元素>=k的矩形元素个数
对于每个查询 我们二分一个 高度
那么答案即为 元素个数-(高度和-查询)/答案高度
预处理 O(M*N*1000) 查询 O(Q*LogH)
对于后50%数据
从矩形变成了线段,那么我们考虑也像上面一样维护一样的东西,只是变成了主席树维护
查询答案也为二分查询 BZOJ卡一下内存
题目链接:
Ac 代码:
#include <cstdio>
#include <iostream>
#define il inline
const int maxm1=5000010;
const int N=1000;
int sum[maxm1*2],v[maxm1*2],ls[maxm1*2],rs[maxm1*2],root[maxm1],sz;
int n,m,q;
int f[202][210][N+10],num[202][202][N+10],mx[210][210];
void insert(int &now,int pre,int l,int r,int k)
{
now=++sz;
ls[now]=ls[pre],rs[now]=rs[pre],sum[now]=sum[pre]+k,v[now]=v[pre]+1;
if(l==r) return;
int mid=(l+r)>>1;
if(k<=mid) insert(ls[now],ls[pre],l,mid,k);
else insert(rs[now],rs[pre],mid+1,r,k);
}
il int getans1(int x,int y,int k)
{
int l=1,r=1000,ans=0;
x=root[x-1],y=root[y];
if(sum[y]-sum[x]<k) return -1;
while(l<r)
{
int mid=(l+r)>>1;
int sumx=sum[rs[y]]-sum[rs[x]];
if(sumx<k)
{
ans+=(v[rs[y]]-v[rs[x]]);
k-=sumx,r=mid;
x=ls[x],y=ls[y];
}
else
{
l=mid+1;
x=rs[x],y=rs[y];
}
}
return ans+(k+l-1)/l;
}
il void work1()
{
for(int i=1,x;i<=m;i++)
scanf("%d",&x),insert(root[i],root[i-1],1,N,x);
for(int i=1;i<=q;i++)
{
int x1,x2,y1,y2,k,d;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
if(~(d=getans1(y1,y2,k))) printf("%d\n",d);
else printf("Poor QLW\n");
}
}
il int getans2(int x1,int y1,int x2,int y2,int k)
{
x1--,y1--;
int l=0,r=N+10;
while(l+1<r)
{
int mid=(l+r)>>1;
if(num[x2][y2][mid]-num[x2][y1][mid]-num[x1][y2][mid]+num[x1][y1][mid]>=k) l=mid;
else r=mid;
}
if(!l) return -1;
int ans1=num[x2][y2][l]-num[x2][y1][l]-num[x1][y2][l]+num[x1][y1][l]-k;
int ans2=f[x2][y2][l]-f[x2][y1][l]-f[x1][y2][l]+f[x1][y1][l];
return ans2-ans1/l;
}
il void work2()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&mx[i][j]);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=1;k<=N;k++)
{
f[i][j][k]=f[i][j-1][k]+f[i-1][j][k]-f[i-1][j-1][k];
num[i][j][k]=num[i][j-1][k]+num[i-1][j][k]-num[i-1][j-1][k];
if (mx[i][j]>=k) f[i][j][k]++,num[i][j][k]+=mx[i][j];
}
for(int i=1;i<=q;i++)
{
int x1,x2,y1,y2,k,d;
scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k);
if(~(d=getans2(x1,y1,x2,y2,k))) printf("%d\n",d);
else printf("Poor QLW\n");
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
if(n==1) work1();
else work2();
return 0;
}