zoukankan      html  css  js  c++  java
  • 【BZOJ4408】[FJOI2016] 神秘数(主席树)

    点此看题面

    • 给定一个长度为(n)的序列(a_i),进行(m)次询问。
    • 每次询问给出一个区间([l,r]),表示用(a_{lsim r})构成一个可重集。求不能用该可重集的子集的和表示的最小正整数。
    • (n,mle 10^5,sum a_ile10^9)

    暴力

    首先,我们把(a_{lsim r})中的数抠出来存到一个数组(s_{1sim t})中,并将其从小到大排序。

    枚举(i),显然只用前(i-1)个数能得到的最大的数为(ans=sum_{k=1}^{i-1}s_k)

    如果(s_ile ans+1),说明(s_i)能够接上前面的答案,那么就继续枚举。

    否则就输出(ans+1),然后(break)

    优化

    假设我们已知当前(ans),显然我们不用傻乎乎去暴力枚举后面的(s_i),而是可以直接将(ans)加上所有(le ans+1)(s_i),然后再去继续处理新的(ans)

    这一过程可以用值域线段树优化。

    关于复杂度,因为每次(ans)差不多至少会翻倍,所有最多操作(O(logn))次。

    又由于是区间询问,只要用主席树就好了。

    代码:(O(nlog^2n))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 100000
    #define LN 20
    using namespace std;
    int n,dc,a[N+5],dv[N+5],Rt[N+5];
    class ChairmanTree//主席树
    {
    	private:
    		int Nt;struct node {int V,S[2];}O[N*LN+5];
    	public:
    		I void Ins(int& rt,CI lst,CI x,CI v,CI l=1,CI r=dc)//单点修改
    		{
    			if((O[rt=++Nt]=O[lst]).V+=v,l==r) return;RI mid=l+r>>1;
    			x<=mid?Ins(O[rt].S[0],O[lst].S[0],x,v,l,mid):Ins(O[rt].S[1],O[lst].S[1],x,v,mid+1,r);
    		}
    		I int Q(CI x,CI y,CI L,CI R,CI l=1,CI r=dc)//区间查询
    		{
    			if(L<=l&&r<=R) return O[x].V-O[y].V;RI mid=l+r>>1;
    			return (L<=mid?Q(O[x].S[0],O[y].S[0],L,R,l,mid):0)+(R>mid?Q(O[x].S[1],O[y].S[1],L,R,mid+1,r):0);
    		}
    }C;
    int main()
    {
    	RI i;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d",a+i),dv[i]=a[i];
    	for(sort(dv+1,dv+n+1),dc=unique(dv+1,dv+n+1)-dv-1,i=1;i<=n;++i)//离散化
    		C.Ins(Rt[i],Rt[i-1],lower_bound(dv+1,dv+dc+1,a[i])-dv,a[i]);//建主席树
    	RI Qt,x,y,t,k,ans;scanf("%d",&Qt);W(Qt--)
    	{
    		scanf("%d%d",&x,&y),ans=k=0;//k表示已经加到了离散化后为k的数
    		W((t=upper_bound(dv+1,dv+dc+1,ans+1)-dv-1)^k) ans+=C.Q(Rt[y],Rt[x-1],k+1,t),k=t;//不断更新ans,每次加上尚未加过的所有小于等于ans+1的a[i]
    		printf("%d
    ",ans+1);//输出ans+1
    	}return 0;
    }
    
  • 相关阅读:
    iOS进阶二-KVC
    iOS进阶一OC对象的本质
    2019-01-19
    2019-01-12
    2019
    2018-12-23 随笔
    2018-12-18 随笔
    2018-12-10
    2018-12-01
    2018.11.23 随笔
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ4408.html
Copyright © 2011-2022 走看看