洛谷P2468 SDOI 2010 粟粟的书架

题意:给你一个矩形书架,每个点是这本书的页数,每次询问(x1,y1)(x2,y2)这个小矩形里最少需要取几本书使得页数和等于Hi。

题解:小数据二位前缀和预处理+二分答案,大数据一行所以用主席树做,感觉数组开得玄学,洛谷上很好过,BZOJ经历了TLE->MLE->CE emmmmm,找不到CE在哪里。

#include<bits/stdc++.h>
#define long long ll
using namespace std;
const int maxn=5e5+100;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,vv;
int val[205][205][1005];
int sum[205][205][1005];
int cc[1005];
int page[205][205];
struct node
{
    int l,r;
    int val,sum;
}no[maxn*20];
inline int get_val(int x1,int y1,int x2,int y2,int k)
{
    return val[x2][y2][k]-val[x1-1][y2][k]-val[x2][y1-1][k]+val[x1-1][y1-1][k];
}
inline int get_sum(int x1,int y1,int x2,int y2,int k)
{
    return sum[x2][y2][k]-sum[x1-1][y2][k]-sum[x2][y1-1][k]+sum[x1-1][y1-1][k];
}
int rs,p,q,pp,qq;
inline void work1()
{
    int tmp=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            page[i][j]=read();
            cc[page[i][j]]++;
            if(page[i][j]>tmp)tmp=page[i][j];
        }
    }
    for(int k=0;k<=tmp;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]+(page[i][j]>=k?page[i][j]:0);
                sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k]+(page[i][j]>=k?1:0);
            }
        }
    }
    while(vv--)
    {
        p=read();q=read();pp=read();qq=read();rs=read();
        if(get_val(p,q,pp,qq,0)<rs)
        {
            printf("Poor QLW\n");
            continue;
        }
        int l=1,r=tmp,ans=-1;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(get_val(p,q,pp,qq,mid)>=rs)l=mid+1,ans=mid;
            else r=mid-1;
        }
        if(ans==-1)printf("Poor QLW\n");
        else{
            int res=get_sum(p,q,pp,qq,ans)-(get_val(p,q,pp,qq,ans)-rs)/ans;
            printf("%d\n",res);
        }
    }
}
int cnt=0;
int ssq[maxn];
int root[maxn];
void build(int &x,int l,int r)
{
    x=++cnt;
    no[x].val=no[x].sum=0;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(no[x].l,l,mid);
    build(no[x].r,mid+1,r);
}
void insertt(int&x,int pre,int l,int r,int pl)
{
    x=++cnt;
    no[x]=no[pre];
    no[x].sum++;
    no[x].val+=pl;
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(pl<=mid)insertt(no[x].l,no[pre].l,l,mid,pl);
    else insertt(no[x].r,no[pre].r,mid+1,r,pl);
}
int query(int x,int pre,int l,int r,int rs)
{
    if(l==r)
    {
        if(rs%l==0)return rs/l;
        return rs/l+1;
    }
    int mid=(l+r)>>1;
    int tmp=no[no[x].r].val-no[no[pre].r].val;
    int ans=0;
    if(tmp<rs)
    {
        rs-=tmp;
        ans+=no[no[x].r].sum-no[no[pre].r].sum;
        ans+=query(no[x].l,no[pre].l,l,mid,rs);
    }
    else{
        ans+=query(no[x].r,no[pre].r,mid+1,r,rs);
    }
    return ans;
}
void work2()
{
    int maxx=0;
    for(int i=1;i<=m;i++)ssq[i]=read(),maxx=max(ssq[i],maxx);
    build(root[0],1,maxx);
    for(int i=1;i<=m;i++)insertt(root[i],root[i-1],1,maxx,ssq[i]);
    while(vv--)
    {
        p=read();q=read();pp=read();qq=read();rs=read();
        if(no[root[qq]].val-no[root[q-1]].val<rs)
        {
            printf("Poor QLW\n");
            continue;
        }
        printf("%d\n",query(root[qq],root[q-1],1,maxx,rs));
    }
}
int main()
{
    n=read();m=read();vv=read();
    if(n==1)work2();
    else work1();
}

  

posted @ 2018-10-01 15:39  Twilight7  阅读(126)  评论(0编辑  收藏  举报