zoukankan      html  css  js  c++  java
  • SDOI2010粟粟的书架

    题目传送:https://www.luogu.org/problemnew/show/P2468

    这是一个二合一的题目,前50% (n!=1)的分数中,我们考虑用动态规划来做。
    (sum[i][j][k])表示大于等于k的([1,1])([i,j])范围内的数的总和,然后用(num[i][j][k])表示数的个数。
    之后就可以用二维前缀和来维护了,具体见代码subtask1

    后50%的题目因为数据范围很大,所以我们只能考虑使用log复杂度的数据结构,因为还涉及到区间排名的问题,所以自然查询的时候要换成主席树。
    不需要离散化。在查询的时候因为是查找大于等于当前查找值的数的个数,所以我们要从右子树开始查找(显然是要从大到小),之后如果右子树的总和大于等于当前查找值,那么就进入右子树,如果不是,那么加上右子树的数的个数然后查找左子树。之后要注意的是如果到了叶子节点,我们要求的个数等于还需要的总和除以该节点值的向上取整。
    具体见代码subtask2

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define MAXN 1000*10+500000*15+10
    int n,m,kkk;
    namespace subtask1
    {
        int maxx=0;
        int sum[210][210][1010],num[210][210][1010],a[1010][1010];
        inline int max(int x,int y){return x>y?x:y;}
        inline int getsum(int x1,int x2,int y1,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];}
        inline int getnum(int x1,int x2,int y1,int y2,int k){return num[x2][y2][k]-num[x1-1][y2][k]-num[x2][y1-1][k]+num[x1-1][y1-1][k];}
        inline void init()
        {
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    scanf("%d",&a[i][j]),maxx=max(maxx,a[i][j]);
            for(int k=0;k<=maxx;k++)
                for(int i=1;i<=n;i++)
                    for(int j=1;j<=m;j++)
                    {
                        sum[i][j][k]=sum[i][j-1][k]+sum[i-1][j][k]-sum[i-1][j-1][k]+(a[i][j]>=k?a[i][j]:0);
                        num[i][j][k]=num[i][j-1][k]+num[i-1][j][k]-num[i-1][j-1][k]+(a[i][j]>=k?1:0);
                    }
        }
        inline void work(int x1,int x2,int y1,int y2,int h)
        {
            if(getsum(x1,x2,y1,y2,0)<h) 
            {
                printf("Poor QLW
    ");
                return;
            }
            int l=0,r=maxx+1,ans=-0x3f;
            while(l<r)
            {
                int mid=(l+r)>>1;
                if(getsum(x1,x2,y1,y2,mid)>=h) ans=mid,l=mid+1;
                else r=mid;
            }
            if(ans==-0x3f) 
            {
                printf("Poor QLW
    ");
                return;
            }
            printf("%d
    ",getnum(x1,x2,y1,y2,ans)-(getsum(x1,x2,y1,y2,ans)-h)/ans); 
        }    
    }
    namespace subtask2
    {
        int cnt;
        int sum[MAXN],siz[MAXN],ls[MAXN],rs[MAXN],rt[MAXN],a[500010];
        inline int max(int x,int y){return x>y?x:y;}
        inline void build(int &x,int l,int r)
        {
            x=++cnt;
            if(l==r) return;
            int mid=(l+r)>>1;
            build(ls[x],l,mid);
            build(rs[x],mid+1,r);
        }
        inline int modify(int x,int l,int r,int p)
        {
            int to=++cnt;
            ls[to]=ls[x],rs[to]=rs[x],siz[to]=siz[x]+1,sum[to]=sum[x]+p;
            if(l==r) return to;
            int mid=(l+r)>>1;
            if(mid<p) rs[to]=modify(rs[to],mid+1,r,p);
            else ls[to]=modify(ls[to],l,mid,p);
            return to;
        }
        inline int query(int u,int v,int l,int r,int k)
        {
            if(l==r) return (k+l-1)/l;
            int mid=(l+r)>>1;
            int x=sum[rs[v]]-sum[rs[u]];
            if(k<=x) return query(rs[u],rs[v],mid+1,r,k);
            else return siz[rs[v]]-siz[rs[u]]+query(ls[u],ls[v],l,mid,k-x);
        }
        inline void work()
        {
            int maxx=0;
            for(int i=1;i<=m;i++) scanf("%d",&a[i]),maxx=max(maxx,a[i]);
            build(rt[0],1,m);
            for(int i=1;i<=m;i++) rt[i]=modify(rt[i-1],1,maxx,a[i]);
            for(int i=1;i<=kkk;i++)
            {
                int cur1,cur2,u,v,h;
                scanf("%d",&cur1),scanf("%d",&u);
                scanf("%d",&cur2),scanf("%d",&v);
                scanf("%d",&h);
                if(sum[rt[v]]-sum[rt[u-1]]<h)
                {
                    printf("Poor QLW
    ");
                    continue;
                }
                printf("%d
    ",query(rt[u-1],rt[v],1,maxx,h));
            }
        }
    }
    using namespace std;
    using namespace subtask1;
    using namespace subtask2;
    int main()
    {
        scanf("%d%d%d",&n,&m,&kkk);
        if(n!=1)
        {
            subtask1::init();
            for(int i=1;i<=kkk;i++)
            {
                int xx1,xx2,yy1,yy2;
                int val;
                scanf("%d%d%d%d%d",&xx1,&yy1,&xx2,&yy2,&val);
                subtask1::work(xx1,xx2,yy1,yy2,val);
            }
        }
        else
            subtask2::work();
        return 0;
    }
    
  • 相关阅读:
    es6 export 和export default的区别
    Vue 中 export及export default的区别
    深入学习jQuery选择器系列第一篇——基础选择器和层级选择器
    深入理解javascript选择器API系列第三篇——HTML5新增的3种selector方法
    深入理解javascript选择器API系列第二篇——getElementsByClassName
    深入理解javascript选择器API系列第一篇——4种元素选择器
    理解jQuery对象$.html
    深入理解DOM节点操作
    深入理解DOM节点关系
    深入理解DOM节点类型第一篇——12种DOM节点类型概述
  • 原文地址:https://www.cnblogs.com/fengxunling/p/10079740.html
Copyright © 2011-2022 走看看