Luogu P4587 [FJOI2016]神祕數

一道好冷門的好題啊,算是對於一個小結論數據結構的一點考驗吧node

首先看完題目咱們發現要從這個神祕數的性質入手,咱們觀察or手玩可得:git

  1. 若是有\(x\)\(1\),那麼\([1,x]\)都是能夠表示出來的
  2. 若是我此時加入的數\(y>x\),那麼這個數沒法被表示,所以便爲答案
  3. 若是我此時加入的數\(y\le x\),那麼這個數能夠被表示,而且能夠表示的區間變成了\([1,x+y]\)

重複以上過程,確定能夠得出答案數據結構

但這樣對於每一次詢問都要進行一次排序,時間複雜度爲\(O(nm\ logn)\),確定跑不過去的。咱們換一種想法,假設我此時已經表示出了\([1,x]\),那麼我統計一下在區間\([l,r]\)中全部小於等於\(x+1\)的數的和\(s\)ide

\(s\ge x+1\),說明此時一定還存在更大的組合方案,因而能夠表示的區間變爲\([1,s]\)ui

再考慮上述的核心過程:統計一段區間內小於等於某個數的數的和spa

直接主席樹便可,把值域線段樹的點權改成數的和便可,查詢的時候仍是分左右子樹查找code

因爲查詢以後每次的答案擴大至少一倍,所以總複雜度\(O(m\ log^2n)\)排序

CODEit

#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
const int N=100005;
struct President_tree
{
    int ch[2],sum;
}node[N*20];
int n,m,q,rt[N],a[N],b[N],tot,l,r;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void write(int x)
{
    if (x>9) write(x/10);
    putchar(x%10+'0');
}
inline int find(int x)
{
    int l=1,r=m,mid,res;
    while (l<=r)
    {
        mid=l+r>>1;
        if (b[mid]<=x) res=mid,l=mid+1; else r=mid-1;
    }
    return res;
}
inline void build(int &now,int l,int r)
{
    if (!now) now=++tot; if (l==r) return; int mid=l+r>>1;
    build(node[now].ch[0],l,mid); build(node[now].ch[1],mid+1,r);
}
inline int insert(int lst,int l,int r,int id,int x)
{
    int now=++tot; node[now]=node[lst]; node[now].sum+=x;
    if (l==r) return now; int mid=l+r>>1;
    if (id<=mid) node[now].ch[0]=insert(node[lst].ch[0],l,mid,id,x);
    else node[now].ch[1]=insert(node[lst].ch[1],mid+1,r,id,x); return now;
}
inline int query(int lst,int now,int l,int r,int beg,int end)
{
    int mid=l+r>>1,res=0;
    if (l>=beg&&r<=end) return node[now].sum-node[lst].sum;
    if (beg<=mid) res+=query(node[lst].ch[0],node[now].ch[0],l,mid,beg,end);
    if (end>mid) res+=query(node[lst].ch[1],node[now].ch[1],mid+1,r,beg,end);
    return res;
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i; read(n);
    for (i=1;i<=n;++i)
    read(a[i]),b[i]=a[i]; read(q);
    sort(b+1,b+n+1); m=unique(b+1,b+n+1)-b-1; build(rt[0],1,m);
    for (i=1;i<=n;++i)
    {
        int x=find(a[i]);
        rt[i]=insert(rt[i-1],1,m,x,a[i]);
    }
    for (i=1;i<=q;++i)
    {
        read(l); read(r); int ans=1;
        for (;;)
        {
            int x=find(ans),s=query(rt[l-1],rt[r],1,m,1,x);
            if (s>=ans) ans=s+1; else break;
        }
        write(ans); putchar('\n');
    }
    return 0;
}
相關文章
相關標籤/搜索