【Luogu】P2468粟粟的书架(主席树+前缀和)
我仿佛中了个爆零debuff
本题分成两部分,五十分用前缀和,f[i][j][k]表示(1,1)到(i,j)的矩形大于等于k的有多少个数(再记录页数和),查询时二分,另外的用主席树,类似方法二分求解,
细节很多需要注意。
#include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #include<cstdlib> #define maxr 220 #define maxc 550000 #define maxv 1000 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } int d[maxr][maxr][maxv+10],s[maxr][maxr][maxv+10]; int tree[maxc*10],root[maxc],ls[maxc*10],rs[maxc*10],tot,size[maxc*10]; int q[maxr][maxr]; int r,c,m; int asks(int xa,int ya,int xb,int yb,int x){ return d[xb][yb][x]-d[xa-1][yb][x]-d[xb][ya-1][x]+d[xa-1][ya-1][x]; } int askn(int xa,int ya,int xb,int yb,int x){ return s[xb][yb][x]-s[xa-1][yb][x]-s[xb][ya-1][x]+s[xa-1][ya-1][x]; } void solve1(){ for(int i=1;i<=r;++i) for(int j=1;j<=c;++j) q[i][j]=read(); for(int k=0;k<=maxv;++k) for(int i=1;i<=r;++i) for(int j=1;j<=c;++j){ bool flag=0; if(q[i][j]<k) flag=1;; d[i][j][k]=d[i-1][j][k]+d[i][j-1][k]-d[i-1][j-1][k]+(flag==0?q[i][j]:0); s[i][j][k]=s[i-1][j][k]+s[i][j-1][k]-s[i-1][j-1][k]+(flag==0?1:0); } while(m--){ int xa=read(),ya=read(),xb=read(),yb=read(),x=read(); if(asks(xa,ya,xb,yb,0)<x){ printf("Poor QLW\n"); continue; } int lef=0,rig=maxv,ans=-1; while(lef<=rig){ int mid=(lef+rig)>>1; //printf("%d>>>%d\n",asks(xa,ya,xb,yb,mid),mid); if(asks(xa,ya,xb,yb,mid)>=x){ ans=mid; lef=mid+1; } else rig=mid-1; } if(ans==-1) printf("Poor QLW\n"); else printf("%d\n",askn(xa,ya,xb,yb,ans)-(asks(xa,ya,xb,yb,ans)-x)/ans); } } inline void update(int &o,int last,int lef,int rig,int p){ o=++tot; ls[o]=ls[last]; rs[o]=rs[last]; tree[o]=tree[last]+p; size[o]=size[last]+1; if(lef==rig) return; int mid=(lef+rig)>>1; if(p<=mid) update(ls[o],ls[last],lef,mid,p); else update(rs[o],rs[last],mid+1,rig,p); } void solve2(){ for(int i=1;i<=c;++i){ int x=read(); update(root[i],root[i-1],1,maxv,x); } while(m--){ int xa=read(),ya=read(),xb=read(),yb=read(),x=read(); if(tree[root[yb]]-tree[root[ya-1]]<x){ printf("Poor QLW\n"); continue; } register int lef=1,rig=maxv,a=root[ya-1],b=root[yb],ans=0; while(lef<rig){ register int mid=(lef+rig)>>1; if(tree[rs[b]]-tree[rs[a]]>=x){ lef=mid+1; a=rs[a]; b=rs[b]; } else{ x-=tree[rs[b]]-tree[rs[a]]; ans+=size[rs[b]]-size[rs[a]]; rig=mid; a=ls[a]; b=ls[b]; } } ans+=(x+lef-1)/lef; printf("%d\n",ans); } return; } int main(){ r=read(),c=read(),m=read(); if(r!=1) solve1(); else solve2(); return 0; }