版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yzyyylx/article/details/82146052
题面
题意
1.给出一个矩形(200*200),每次询问给出一个子矩形和一个数,问在这个子矩形中至少选几个数,使它们的和大于等于给出的数。
2.给出一列数(500000),每次询问给出一个区间和一个数,问在这个区间中至少选几个数,使它们的和大于等于给出的数。
做法
考虑二分选出数的最小值,这样问题就转化为了:每次判断某个范围内大于等于某数的和是否大于等于给出数。
1.只要用二维前缀和维护即可:
sum[i][j][k]表示(1,1)与(i,j)构成的矩形中大于等于k的数的和
cnt[i][j][k]表示(1,1)与(i,j)构成的矩形中大于等于k的数的个数
2.用主席树维护每一个最小值下的线段树,每次查询区间和即可
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#define M 1010
#define MN 1000
using namespace std;
int n,m,Q;
#define N 210
namespace solve1
{
int num[N][N],sum[N][N][M],cnt[N][N][M],a,b,c,d,e,ans;
inline int judge(int u)
{
return sum[c][d][u]+sum[a-1][b-1][u]-sum[a-1][d][u]-sum[c][b-1][u]-e;
}
inline int ask(int u)
{
return cnt[c][d][u]+cnt[a-1][b-1][u]-cnt[a-1][d][u]-cnt[c][b-1][u];
}
void work()
{
int i,j,k,l,r,mid,tmp,t;
for(i=1; i<=m; i++)
{
for(j=1; j<=n; j++)
{
scanf("%d",&num[i][j]);
}
}
for(k=1; k<=MN; k++)
{
for(i=1; i<=m; i++)
{
for(j=1; j<=n; j++)
{
if(num[i][j]>=k) sum[i][j][k]=num[i][j],cnt[i][j][k]=1;
sum[i][j][k]+=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k];
cnt[i][j][k]+=cnt[i-1][j][k]+cnt[i][j-1][k]-cnt[i-1][j-1][k];
}
}
}
for(i=1; i<=Q; i++)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&e);
for(l=1,r=MN+1; l<r;)
{
mid=((l+r)>>1);
judge(mid)>=0?l=mid+1:r=mid;
}
l--;
if(!l)
{
puts("Poor QLW");
continue;
}
ans=ask(l);
t=ans-ask(l+1);
tmp=judge(l);
for(; t&&tmp-l>=0; t--,ans--,tmp-=l);
printf("%d\n",ans);
}
}
}
#undef N
#define N 500100
namespace solve2
{
int num[N],pos[N],tt,lt,rt[M],a,b,e,ans;
struct Node
{
int ls,rs,sum,cnt;
} node[N*20];
inline bool cmp(int u,int v)
{
return num[u]>num[v];
}
inline void up(int u)
{
int L=node[u].ls,R=node[u].rs;
node[u].sum=node[L].sum+node[R].sum;
node[u].cnt=node[L].cnt+node[R].cnt;
}
void build(int now,int l,int r)
{
if(l==r) return;
int mid=((l+r)>>1);
node[now].ls=++tt;
build(tt,l,mid);
node[now].rs=++tt;
build(tt,mid+1,r);
}
void add(int now,int l,int r,int u)
{
if(l==r)
{
node[now].cnt=1;
node[now].sum=num[u];
return;
}
int mid=((l+r)>>1);
if(u<=mid)
{
if(node[now].ls<=lt)
{
node[++tt]=node[node[now].ls];
node[now].ls=tt;
}
add(node[now].ls,l,mid,u);
}
else
{
if(node[now].rs<=lt)
{
node[++tt]=node[node[now].rs];
node[now].rs=tt;
}
add(node[now].rs,mid+1,r,u);
}
up(now);
}
int asks(int now,int l,int r,int u,int v)
{
if(l==u&&v==r) return node[now].sum;
int mid=((l+r)>>1),res=0;
if(u<=mid) res+=asks(node[now].ls,l,mid,u,min(mid,v));
if(mid<v) res+=asks(node[now].rs,mid+1,r,max(u,mid+1),v);
return res;
}
int askc(int now,int l,int r,int u,int v)
{
if(l==u&&v==r) return node[now].cnt;
int mid=((l+r)>>1),res=0;
if(u<=mid) res+=askc(node[now].ls,l,mid,u,min(mid,v));
if(mid<v) res+=askc(node[now].rs,mid+1,r,max(u,mid+1),v);
return res;
}
void work()
{
int i,j,l,r,mid,t,tmp;
for(i=1; i<=n; i++) scanf("%d",&num[i]),pos[i]=i;
sort(pos+1,pos+n+1,cmp);
rt[MN+1]=1;
build(++tt,1,n);
for(i=MN,j=1; i>=1;i--)
{
lt=tt;
rt[i]=++tt;
node[tt]=node[rt[i+1]];
for(; num[pos[j]]==i;j++)
{
add(rt[i],1,n,pos[j]);
}
}
for(i=1;i<=Q;i++)
{
scanf("%*d%d%*d%d%d",&a,&b,&e);
for(l=1,r=MN+1;l<r;)
{
mid=((l+r)>>1);
asks(rt[mid],1,n,a,b)>=e?l=mid+1:r=mid;
}
l--;
if(!l)
{
puts("Poor QLW");
continue;
}
ans=askc(rt[l],1,n,a,b);
t=ans-askc(rt[l+1],1,n,a,b);
tmp=asks(rt[l],1,n,a,b)-e;
for(; t&&tmp-l>=0; t--,ans--,tmp-=l);
printf("%d\n",ans);
}
}
}
int main()
{
int i,j;
cin>>m>>n>>Q;
if(m>1) solve1::work();
else solve2::work();
}