BZOJ 1926: [Sdoi2010]粟粟的书架【二分+主席树】
1926: [Sdoi2010]粟粟的书架
【题目描述】
传送门
【题解】
这题肯定是让我们分类讨论的。
R,C≤200时,荣斥+二分查找:
表示从(1,1)到(i,j)大于k的和,表示从(1,1)到(i,j)大于k的个数,那么我们二分这个k,荣斥套一下就可以了。
不过要注意,当k有多个时,不一定要全部用掉,所以还要减去没用的。
R=1,C≤500000时,主席树套一下就可以了。
代码如下
#include<cstdio>
#include<cctype>
#define MAXN 500005
using namespace std;
int n,m,q,cnt,Ans1,Ans2,Ans3,mp[205][205],Val[205][205][1005],Num[205][205][1005];
int x1,y1,x2,y2,K,T[MAXN],Tre[MAXN*20],Sum[MAXN*20],L[MAXN*20],R[MAXN*20];
bool check(int x){
if(Val[x2][y2][x]-Val[x2][y1-1][x]-Val[x1-1][y2][x]+Val[x1-1][y1-1][x]>=K){
Ans1=Val[x2][y2][x]-Val[x2][y1-1][x]-Val[x1-1][y2][x]+Val[x1-1][y1-1][x];
Ans2=Num[x2][y2][x]-Num[x2][y1-1][x]-Num[x1-1][y2][x]+Num[x1-1][y1-1][x];
return 1;
}else return 0;
}
int Updata(int lst,int l,int r,int x){
int rt=++cnt;
L[rt]=L[lst];R[rt]=R[lst];Tre[rt]=Tre[lst]+1;Sum[rt]=Sum[lst]+x;
if(l<r){
int mid=(r+l)>>1;
if(x<=mid) L[rt]=Updata(L[lst],l,mid,x);
else R[rt]=Updata(R[lst],mid+1,r,x);
}
return rt;
}
int Query(int u,int v,int l,int r,int p){
int Ans=0;
while(l<r){
int Now=Sum[R[v]]-Sum[R[u]],mid=(r+l)>>1;
if(p<=Now) u=R[u],v=R[v],l=mid+1;
else Ans+=Tre[R[v]]-Tre[R[u]],p-=Now,r=mid,u=L[u],v=L[v];
}
Ans+=(p+l-1)/l;
return Ans;
}
int read(){
int ret=0;char ch=getchar();bool f=1;
for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
for(; isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-48;
return f?ret:-ret;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1926.in","r",stdin);
freopen("1926.out","w",stdout);
#endif
n=read(),m=read(),q=read();
if(n>1){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++) mp[i][j]=read();
for(int k=1000;k;k--)
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
Val[i][j][k]=Val[i-1][j][k]+Val[i][j-1][k]-Val[i-1][j-1][k]+(mp[i][j]>=k?mp[i][j]:0),
Num[i][j][k]=Num[i-1][j][k]+Num[i][j-1][k]-Num[i-1][j-1][k]+(mp[i][j]>=k);
for(int i=1;i<=q;i++){
Ans1=-1;
x1=read(),y1=read(),x2=read(),y2=read(),K=read();
if(!check(1)){printf("Poor QLW\n");continue;}
for(int L=1,R=1000,mid=(R+L)>>1;L<=R;mid=(R+L)>>1)
if(check(mid)) Ans3=mid,L=mid+1;else R=mid-1;
printf("%d\n",Ans2-(Ans1-K)/Ans3);
}
}else{
for(int i=1;i<=m;i++){
int x=read();
T[i]=Updata(T[i-1],1,1000,x);
}
for(int i=1;i<=q;i++){
int l,r,p;read();l=read();read();r=read();p=read();
if(Sum[T[r]]-Sum[T[l-1]]>=p) printf("%d\n",Query(T[l-1],T[r],1,1000,p));
else printf("Poor QLW\n");
}
}
return 0;
}