1. 程式人生 > >【BZOJ4408】[FJOI2016]神秘數(主席樹)

【BZOJ4408】[FJOI2016]神秘數(主席樹)

直接 當前 def 依次 != tps ++i lin inline

【BZOJ4408】[FJOI2016]神秘數(主席樹)

題面

BZOJ
洛谷

題解

考慮只有一次詢問。
我們把所有數排個序,假設當前可以表示出的最大數是\(x\)
起始\(x=0\)
依次考慮接下來的每個數\(a_i\),如果\(a_i\le x\),那麽沒有啥問題,\(x+=a_i\)
如果\(a_i=x+1\),那麽也沒有問題,\(x+=a_i\)
如果\(a_i>x\),那麽\(x+1\)就拼不出來了。
那麽顯然考慮每次詢問,首先把所有\(\le x\)的數全部加進來,然後考慮下一個比\(x\)大的數,如果其大於\(x+1\),那麽直接就\(GG\)了。
否則等於\(x+1\)

,意味著\(x\)至少要翻一倍。
因此最多執行\(log\)次翻倍的操作。
抄起主席樹暴力維護就好了。

#include<iostream>
#include<cstdio>
using namespace std;
#define MAX 100100
inline int read()
{
    int x=0;bool t=false;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=true,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return t?-x:x;
}
struct Node{int ls,rs,v;}t[MAX*35];int tot;
void Modify(int &x,int l,int r,int p)
{
    t[++tot]=t[x];x=tot;t[x].v+=p;
    if(l==r)return;int mid=(l+r)>>1;
    if(p<=mid)Modify(t[x].ls,l,mid,p);
    else Modify(t[x].rs,mid+1,r,p);
}
int Query(int x,int y,int l,int r,int p)
{
    if(l==r)return t[x].v-t[y].v;int mid=(l+r)>>1;
    if(p<=mid)return Query(t[x].ls,t[y].ls,l,mid,p);
    else return Query(t[x].rs,t[y].rs,mid+1,r,p)+t[t[x].ls].v-t[t[y].ls].v;
}
int n,m,a[MAX],rt[MAX];
int main()
{
    n=read();
    for(int i=1;i<=n;++i)a[i]=read();
    for(int i=1;i<=n;++i)Modify(rt[i]=rt[i-1],1,1e9,a[i]);
    m=read();
    while(m--)
    {
        int l=read(),r=read(),x=0;
        while(x<1e9)
        {
            int v=Query(rt[r],rt[l-1],1,1e9,x+1);
            if(v==x)break;x=v;
        }
        printf("%d\n",x+1);
    }
    return 0;
}

【BZOJ4408】[FJOI2016]神秘數(主席樹)