[BZOJ1926][SDOI2010]粟粟的书架

BZOJ
Luogu
Description
幸福幼儿园 B29 班的粟粟是一个聪明机灵、乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Cormen 的文章。粟粟家中有一个 R行C列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行、左数第j 列
摆放的书有Pi,j页厚。粟粟每天除了读书之外,还有一件必不可少的工作就是摘苹果,她每天必须摘取一个指定的苹果。粟粟家果树上的苹果有的高、有的低,但无论如何凭粟粟自己的个头都难以摘到。不过她发现, 如果在脚下放上几本书,就可以够着苹果;她同时注意到,对于第 i天指定的那个苹果,只要她脚下放置书的总页数之和不低于Hi,就一定能够摘到。由于书架内的书过多,父母担心粟粟一天内就把所有书看完而耽误了上幼儿园,于是每天只允许粟粟在一个特定区域内拿书。这个区域是一个矩形,第 i天给定区域的左上角是上数第 x1i行的左数第 y1i本书,右下角是上数第x2i行的左数第y2i本书。换句话说,粟粟在这一天,只能在这﹙x2i-x1i+1﹚×﹙y2i-y1i+1﹚本书中挑选若干本垫在脚下,摘取苹果。粟粟每次取书时都能及时放回原位,并且她的书架不会再撤下书目或换上新书,摘苹果的任务会一直持续M天。给出每本书籍的页数和每天的区域限制及采摘要求,请你告诉粟粟,她每天至少拿取多少本书,就可以摘到当天指定的苹果。
Input
第一行是三个正整数R,C,M。
接下来是一个R行C列的矩阵,从上到下、从左向右依次给出了每本书的页数Pi,j。
接下来M行,第i行给出正整数x1i,y1i,x2i,y2i,Hi,表示第i天的指定区域是﹙x1i,y1i﹚与﹙x2i,y2i﹚间的矩形,总页数之和要求不低于Hi。
保证1≤x1i≤x2i≤R,1≤y1i≤y2i≤C。
Output
有M行,第i 行回答粟粟在第 i天时为摘到苹果至少需要拿取多少本书。如果即使取走所有书都无法摘到苹果,则在该行输出“Poor QLW” (不含引号)。
输入样例#1:

5 5 7
14 15 9 26 53
58 9 7 9 32
38 46 26 43 38
32 7 9 50 28
8 41 9 7 17
1 2 5 3 139
3 1 5 5 399
3 3 4 5 91
4 1 4 1 33
1 3 5 4 185
3 3 4 3 23
3 1 3 3 108

输出样例#1:

6
15
2
Poor QLW
9
1
3

输入样例#2:

1 10 7
14 15 9 26 53 58 9 7 9 32
1 2 1 9 170
1 2 1 9 171
1 5 1 7 115
1 1 1 10 228
1 4 1 4 45704571
1 1 1 1 1
1 7 1 8 16

输出样例#2:

6
7
3
10
Poor QLW
1
2

HINT
对于 10%的数据,满足 R, C≤10;
对于 20%的数据,满足 R, C≤40;
对于 50%的数据,满足 R, C≤200,M≤200,000;
另有 50%的数据,满足 R=1,C≤500,000,M≤20,000;
对于 100%的数据,满足 1≤Pi,j≤1,000,1≤Hi≤2,000,000,000

sol

神奇的题目。很明显看数据范围就知道是两道题目强行拼在一起的。
对于前50%的数据,考虑到是一个200*200的矩阵,所以就考虑二维前缀和维护。
\(num_{i,j,k}\)表示前\(i\)行前\(j\)列内页数大于等于\(k\)的书的本数。
\(sum_{i,j,k}\)表示前\(i\)行前\(j\)列内页数大于等于\(k\)的书的页数和。
易知这两个东西可以\(O(n^2*1000)\)递推。
然后在查询的时候二分\(k\),注意处理某一种页数的书只取一部分的情况。
时间复杂度\(O(RC*1000+M*log_{2}1000)\) 空间复杂度\(O(2*RC*1000)\)
对于后50%的数据,矩阵退化成长链,所以我们可以使用主席树维护数列前缀在一个页数区间内的书本总数和页数和。
查询就是两棵主席树作减法,注意是优先选择页数大的书本,所以在查询时递归调用左还是右子树的时候要想清楚,不要凭惯性思维。
同样要注意某一种页数的书不取完只取一部分的情况。
时间复杂度是\(O(C*log_{2}1000+M*log_{2}1000)\) 空间复杂度\(O(4*C*log_{2}1000)\)(因为主席树要维护四个东西)

空间看上去很炸,但的确没有超过\(512MB\)(这题要是卡空间那不就不可做了?)

code

居然才80行,真是出奇的短

#include<cstdio>
#include<algorithm>
using namespace std;
int R,C,M,x1,y1,x2,y2,H;
int gi()
{
    int x=0,w=1;char ch=getchar();
    while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    if (ch=='-') w=0,ch=getchar();
    while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return w?x:-x;
}

int val[202][202],num[202][202][1002],sum[202][202][1002],l,r;
int Sum(int k){return sum[x2][y2][k]-sum[x1-1][y2][k]-sum[x2][y1-1][k]+sum[x1-1][y1-1][k];}
int Num(int k){return num[x2][y2][k]-num[x1-1][y2][k]-num[x2][y1-1][k]+num[x1-1][y1-1][k];}
void work1()
{
    for (int i=1;i<=R;i++)
        for (int j=1;j<=C;j++)
            val[i][j]=gi();
    for (int i=1;i<=R;i++)
        for (int j=1;j<=C;j++)
            for (int k=1;k<=1000;k++)
            {
                num[i][j][k]=num[i-1][j][k]+num[i][j-1][k]-num[i-1][j-1][k]+(val[i][j]>=k?1:0);
                sum[i][j][k]=sum[i-1][j][k]+sum[i][j-1][k]-sum[i-1][j-1][k]+(val[i][j]>=k?val[i][j]:0);
            }
    while (M--)
    {
        x1=gi();y1=gi();x2=gi();y2=gi();H=gi();
        l=0;r=1000;
        while (l<r)
        {
            int mid=l+r+1>>1;
            if (Sum(mid)>=H) l=mid;
            else r=mid-1;
        }
        if (!l) puts("Poor QLW");
        else printf("%d\n",Num(l)-(Sum(l)-H)/l);
    }
}
struct president_tree{int ls,rs,num,sum;}t[10000000];
int rt[500005],tot;
void update(int &x,int l,int r,int pos)
{
    t[++tot]=t[x];
    t[x=tot].num++;t[x].sum+=pos;
    if (l==r) return;
    int mid=l+r>>1;
    if (pos<=mid) update(t[x].ls,l,mid,pos);
    else update(t[x].rs,mid+1,r,pos);
}
int query(int A,int B,int l,int r)
{
    if (l==r) return (H+l-1)/l;
    int k=t[t[A].rs].sum-t[t[B].rs].sum,mid=l+r>>1;
    if (k>=H) return query(t[A].rs,t[B].rs,mid+1,r);
    else {H-=k;return t[t[A].rs].num-t[t[B].rs].num+query(t[A].ls,t[B].ls,l,mid);}
}
void work2()
{
    for (int i=1;i<=C;i++)
    {
        rt[i]=rt[i-1];
        int x=gi();update(rt[i],1,1000,x);
    }
    while (M--)
    {
        gi();y1=gi();gi();y2=gi();H=gi();
        if (t[rt[y2]].sum-t[rt[y1-1]].sum<H) puts("Poor QLW");
        else printf("%d\n",query(rt[y2],rt[y1-1],1,1000));
    }
}
int main()
{
    R=gi();C=gi();M=gi();
    if (R>1) work1();
    else work2();
    return 0;
}
posted @ 2018-01-02 22:14  租酥雨  阅读(...)  评论(...编辑  收藏