zoukankan      html  css  js  c++  java
  • bzoj 4408

    嗯..

    首先考虑如果只有一次询问我们怎么做

    设我们当前有个数集{$S$},进行这一询问,我们怎么处理?

    首先不妨假设{$S$}单调不降(如果不是这样的话显然排序并不会影响答案)

    那么假设前$i$个数都合法,其能组合出的最大的值为$lim$,那么我们只需比较$S_{i+1}$与$lim+1$的大小就可以确定答案是否增大

    为什么?

    前$i$个数能够表示出$lim$,而如果$S_{i+1}<=lim$,那么一定能表示出$[lim+1,lim+S_{i+1}]$!

    为什么?

    我们钦定$S_{i+1}$必选,那么我们为了表示出$[lim+1,lim+S_{i+1}]$这些数,我们只需用$1~i$的数表示出$[lim+1-S_{i+1},lim]$即可

    考虑到要求$1~i$一定能表示出$[0,lim]$,因此只需要求$lim+1-S_{i+1}geq 0$即可

    也即$S_{i+1}leq lim+1$

    因此如果只有一次询问,我们只需从前向后扫即可

    但是现在是多次询问啊!

    没有关系,我们考虑上面操作的等价条件:

    我们发现,上面操作算出的答案一定满足:将所有小于等于答案的原集合中的数求和等于答案-1!

    因此我们只需利用这一性质即可

    从1开始枚举一个答案,然后检验区间中小于等于这个答案的数求和是否大于这个答案即可

    为了求出区间小于等于某个答案的数的和,需要用可持久化的权值线段树实现

    代码很好写

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define ll long long
    #define ls tree[rt].lson
    #define rs tree[rt].rson
    using namespace std;
    const int lim=1000000000;
    struct Pre_Seg_Tree
    {
        int lson,rson;
        ll sum;
    }tree[8000005];
    ll v[100005];
    int rot[100005];
    int n,m,tot;
    void update(int rt)
    {
        tree[rt].sum=tree[ls].sum+tree[rs].sum;
    }
    void ins(int &rt,int lrt,int l,int r,ll pos)
    {
        rt=++tot;
        if(l==r){tree[rt].sum=tree[lrt].sum+1ll*pos;return;}
        int mid=(l+r)>>1;
        if(pos<=mid)rs=tree[lrt].rson,ins(ls,tree[lrt].lson,l,mid,pos);
        else ls=tree[lrt].lson,ins(rs,tree[lrt].rson,mid+1,r,pos);
        update(rt);
    }
    ll query(int rt1,int rt2,int l,int r,int lq,int rq)
    {
        if(l>=lq&&r<=rq)return tree[rt2].sum-tree[rt1].sum;
        int mid=(l+r)>>1;
        ll s=0;
        if(lq<=mid)s+=query(tree[rt1].lson,tree[rt2].lson,l,mid,lq,rq);
        if(rq>mid)s+=query(tree[rt1].rson,tree[rt2].rson,mid+1,r,lq,rq);
        return s;
    }
    template <typename T> inline void read(T &x)
    {
        T f=1,c=0;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
        x=c*f;
    }
    int main()
    {
        read(n);
        for(int i=1;i<=n;i++)read(v[i]),ins(rot[i],rot[i-1],1,lim,v[i]);
        read(m);
        while(m--)
        {
            int l,r;
            read(l),read(r);
            ll ans=1;
            while(1)
            {
                ll sum=query(rot[l-1],rot[r],1,lim,1,ans);
                if(sum<ans)break;
                ans=sum+1;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    九度 1172:哈夫曼树
    mac os 错误提示:下载失败 使用已购页面再试一次 解决方法
    WCF学习资料汇总
    豆瓣FM 歌词跟随插件
    大型网站架构和高并发的一些想法
    MAC OS 系统使用心得
    Windows 7 安装.net framework 4.0 失败,错误HRESULT 0xc8000222解决办法
    json官方学习档案
    转:查看sql语句执行时间/测试sql语句性能
    从数据库反向生成django的models
  • 原文地址:https://www.cnblogs.com/zhangleo/p/11088667.html
Copyright © 2011-2022 走看看