bzoj1926: [Sdoi2010]粟粟的书架

来源:互联网 发布:股票交易软件 策略 编辑:程序博客网 时间:2024/05/16 09:37

传送门
对于第一问(R,C<=200);
预处理f[x][y][k],s[x][y][k].表示从(1,1)到(x,y)中大于等于k的数的和与大于等于k的数的个数。
然后二分最小的数即可。
对于第二问(R=1):
我们还是二分最小数。
判断就变成了询问一段区间内大于等于x的数的和以及它们的个数。
显然主席树可以处理这个

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<queue>#define N 11000000#define M 210 using namespace std;int n,m,T,a[M][M][M*5],b[M][M][M*5],c[M][M],x1,y1,x2,y2,h;int t,rt[550000],ls[N],rs[N],v[N],s[N],cnt;void work1(){    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++) scanf("%d",&c[i][j]);    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)            for (int k=1;k<=1000;k++){                a[i][j][k]=a[i][j-1][k]+a[i-1][j][k]-a[i-1][j-1][k];                b[i][j][k]=b[i][j-1][k]+b[i-1][j][k]-b[i-1][j-1][k];                if (c[i][j]>=k) a[i][j][k]++,b[i][j][k]+=c[i][j];            }    while (T--){        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&h);        int l=0,r=1001; x1--; y1--;        while (l+1<r){            int mid=(l+r)/2;            if (b[x1][y1][mid]+b[x2][y2][mid]-b[x1][y2][mid]-b[x2][y1][mid]>=h)                l=mid; else r=mid;        }        if (l==0) puts("Poor QLW");        else{            int sum1=b[x1][y1][l]+b[x2][y2][l]-b[x2][y1][l]-b[x1][y2][l]-h;            int sum2=a[x1][y1][l]+a[x2][y2][l]-a[x2][y1][l]-a[x1][y2][l];            printf("%d\n",sum2-sum1/l);        }    }}void add(int l,int r,int x,int &y,int k){    y=++cnt; v[y]=v[x]+1; s[y]=s[x]+k;    if (l==r) return;    int mid=(l+r)/2;    if (k<=mid) rs[y]=rs[x],add(l,mid,ls[x],ls[y],k);    else ls[y]=ls[x],add(mid+1,r,rs[x],rs[y],k);}int ask(int x,int y,int k){    int l=1,r=1000,ok=0;    x=rt[x-1]; y=rt[y];    if (s[y]-s[x]<h) return -1;    while (l<r){        int mid=(l+r)/2,t=s[rs[y]]-s[rs[x]];        if (t<k){            ok+=v[rs[y]]-v[rs[x]]; k-=t; r=mid;            x=ls[x]; y=ls[y];        }        else{            l=mid+1; x=rs[x]; y=rs[y];        }    }    ok+=(k+l-1)/l;    return ok;}void work2(){    for (int i=1,x;i<=m;i++){        scanf("%d",&x);        add(1,1000,rt[i-1],rt[i],x);    }    while (T--){        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&h);        int ans=ask(y1,y2,h);        if (ans==-1) puts("Poor QLW");        else printf("%d\n",ans);    }}int main(){    scanf("%d%d%d",&n,&m,&T);    if (n!=1) work1(); else work2();}
原创粉丝点击