正解:主席树

解题报告:

先放下传送门QAQ

首先可以先思考如果只有一组询问,怎么解决

可以这么想,最开始一个数也麻油的时候能表示的最大的数是0嘛

然后先排个序,按顺序每次新加入一个数x,设加入这个数之前能表示的最大的数是y

首先显然的是如果x>y+1,y+1一定不能被表示出来,就GG了

如果x<=y+1,那么能表示出来的最大的数就一定是x+y,就更新一下y+=x

从上面这个式子我们可以得到实际上每加入一个数,当可以继续下去的时候其实就是y=∑x

然后现在考虑是有多组询问的鸭怎么搞呢QAQ?

可以考虑这样子:对于当前的x,查询<=x的数的和

那显然就是线段树,存[l,r]的和,非常基础的套路辣

然后因为是问的区间内,所以用个主席树就好

然后就麻油啦啦啦!

洛谷P4587 神秘数 [FJOI2016] 主席树洛谷P4587 神秘数 [FJOI2016] 主席树
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ll long long
#define gc getchar()
#define t(i) edge[i].to
#define w(i) edge[i].wei
#define ri register int
#define rb register bool
#define rc register char
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define e(i,x) for(ri i=head[x];~i;i=edge[i].nxt)

const int N=100000+10,inf=1e9,M=1e8;
int n,m,rt[N],nod_cnt;
bool gdgs=1;
struct chtr{int ls,rs,dat;}tr[M];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il int modify(ri x,ri l,ri r,ri dat)
{
    ri nw=++nod_cnt;
    tr[nw]=tr[x];tr[nw].dat+=dat;if(l==r)return nw;
    if(dat<=((l+r)>>1))tr[nw].ls=modify(tr[x].ls,l,(l+r)>>1,dat);else tr[nw].rs=modify(tr[x].rs,((l+r)>>1)+1,r,dat);return nw;
}
il int query(int x1,int x2,int l,int r,int dat)
{
    if(l==r)return tr[x2].dat-tr[x1].dat;
    if(dat<=((l+r)>>1))return query(tr[x1].ls,tr[x2].ls,l,(l+r)>>1,dat);return tr[tr[x2].ls].dat-tr[tr[x1].ls].dat+query(tr[x1].rs,tr[x2].rs,((l+r)>>1)+1,r,dat);
}

int main()
{
//    freopen("4587.in","r",stdin);freopen("4587.out","w",stdout);
    n=read();rp(i,1,n)rt[i]=modify(rt[i-1],1,inf,read());
    m=read();while(m--){int l=read(),r=read(),as=0;while(gdgs){int tmp=query(rt[l-1],rt[r],1,inf,as+1);if(tmp==as)break;as=tmp;}printf("%d\n",as+1);}
    return 0;
}
这儿是代码QwQ!

相关文章: