题解:
这是两道题
前50%:
发现p[i][j]很小,于是记录f[i][j][k]表示(1,1)~(i,j)这个子矩阵内>=k的书的总高度,g[i][j][k]记录本数
查询是二分答案就好了
后50%:
主席树,右子树够了就向右走,否则向左走
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m,T; int PTsiz; int root[500009]; struct PresidentTree{ int ls,rs,d,sum; }tree[10000009]; void BuildTree(int &now,int l,int r){ now=++PTsiz; tree[now].d=tree[now].sum=0; if(l==r)return; int mid=(l+r)>>1; BuildTree(tree[now].ls,l,mid); BuildTree(tree[now].rs,mid+1,r); } void Updatapoint(int &now,int pre,int p,int x,int l,int r){ now=++PTsiz; tree[now]=tree[pre]; tree[now].d++;tree[now].sum+=x; // cout<<"shit"<<tree[now].l<<‘ ‘<<tree[now].r<<endl; if(l==r)return; int mid=(l+r)>>1; if(p<=mid)Updatapoint(tree[now].ls,tree[pre].ls,p,x,l,mid); else Updatapoint(tree[now].rs,tree[pre].rs,p,x,mid+1,r); } int a[500009]; int b[500009],nn; int sum2[500009]; int Queryamount(int now,int pre,int tot,int l,int r){ if(l==r){ int x=b[l]; if(tot%x==0)return tot/x; else return tot/x+1; } int s=tree[tree[now].rs].sum-tree[tree[pre].rs].sum; int d=tree[tree[now].rs].d-tree[tree[pre].rs].d; // printf("%d %d %d %d\n",b[tree[now].l],b[tree[now].r],d,s); // if(s==tot)return d; int mid=(l+r)>>1; if(s<tot)return d+Queryamount(tree[now].ls,tree[pre].ls,tot-s,l,mid); else return Queryamount(tree[now].rs,tree[pre].rs,tot,mid+1,r); } const int u=1000; int f[209][209][u+10];//amount int g[209][209][u+10];//sum int c[209][209]; int Getans(int x,int y,int xx,int yy,int s){ int l=1,r=u,mid,ans=1; while(l<=r){ mid=(l+r)>>1; int tmp=g[xx][yy][mid]-g[xx][y-1][mid]-g[x-1][yy][mid]+g[x-1][y-1][mid]; if(tmp>=s){ ans=mid;l=mid+1; }else{ r=mid-1; } } int tmp=f[xx][yy][ans]-f[xx][y-1][ans]-f[x-1][yy][ans]+f[x-1][y-1][ans]; int tmp2=g[xx][yy][ans]-g[xx][y-1][ans]-g[x-1][yy][ans]+g[x-1][y-1][ans]; return tmp-(tmp2-s)/ans; // return tmp; } int Workans1(){ for(int i=1;i<=n;++i){ for(int j=1;j<=m;++j){ scanf("%d",&c[i][j]); for(int k=0;k<=u;++k){ f[i][j][k]=f[i][j-1][k]+f[i-1][j][k]-f[i-1][j-1][k]; g[i][j][k]=g[i][j-1][k]+g[i-1][j][k]-g[i-1][j-1][k]; if(k<=c[i][j]){ f[i][j][k]+=1; g[i][j][k]+=c[i][j]; } } } } while(T--){ int x,y,xx,yy,s; scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&s); int maxsum=g[xx][yy][0]-g[x-1][yy][0]-g[xx][y-1][0]+g[x-1][y-1][0]; if(maxsum<s)printf("Poor QLW\n"); else printf("%d\n",Getans(x,y,xx,yy,s)); } } int Workans2(){ for(int i=1;i<=m;++i){ scanf("%d",&a[i]);b[i]=a[i];sum2[i]=a[i]+sum2[i-1]; } sort(b+1,b+1+m); nn=unique(b+1,b+1+m)-b-1; BuildTree(root[0],1,nn); for(int i=1;i<=m;++i)Updatapoint(root[i],root[i-1],lower_bound(b+1,b+1+nn,a[i])-b,a[i],1,nn); while(T--){ int x,y,xx,yy,s; scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&s); int tmp=Queryamount(root[yy],root[y-1],s,1,nn); if(sum2[yy]-sum2[y-1]>=s)printf("%d\n",tmp); else printf("Poor QLW\n"); } } int main(){ scanf("%d%d%d",&n,&m,&T); if(n!=1)Workans1(); else Workans2(); return 0; }