題目連接php
記mx爲最大的知足1~mx都能組成的數。
考慮當前能構成1~v中的全部數,再加入一個數x,若x>v+1,則mx=v,x不會產生影響;不然x<=v+1,則新的mx=x+v。
對於區間[l,r]的詢問,模擬這個過程。假設當前答案爲v,查詢[l,r]中值在[1,v+1]中的數的和sum,若sum==v,即不存在v+1,break;不然v加上這些v+1的和即v=sum,繼續。
用主席樹實現。v每次至少增長一倍(好像這麼說不恰當,每次加的數至少是上一個數+1?),因此複雜度\(O(n\log n\log a)\)。git
爲何跑的比較慢呢。。spa
//38224kb 2860ms #include <cstdio> #include <cctype> #include <algorithm> //#define gc() getchar() #define MAXIN 300000 #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++) const int N=1e5+5; int A[N],root[N]; char IN[MAXIN],*SS=IN,*TT=IN; struct Tree { #define S N*31//loga not logn && 31 not 30... #define lson son[x][0] #define rson son[x][1] int tot,sum[S],son[S][2]; inline void Insert(int x,int &y,int l,int r,int p) { sum[y=++tot]=sum[x]+p; if(l==r) return; int m=l+r>>1; if(p<=m) son[y][1]=rson, Insert(lson,son[y][0],l,m,p); else son[y][0]=lson, Insert(rson,son[y][1],m+1,r,p); } int Query(int x,int y,int l,int r,int R) { if(r<=R) return sum[y]-sum[x]; int m=l+r>>1; if(m<R) return sum[son[y][0]]-sum[lson]+Query(rson,son[y][1],m+1,r,R); else return Query(lson,son[y][0],l,m,R); } }T; inline int read() { int now=0;register char c=gc(); for(;!isdigit(c);c=gc()); for(;isdigit(c);now=now*10+c-'0',c=gc()); return now; } int main() { int n=read(); int R=1; for(int i=1; i<=n; ++i) R+=(A[i]=read()); for(int i=1; i<=n; ++i) T.Insert(root[i-1],root[i],1,R,A[i]); for(int m=read(),l,r,ans,sum; m--; ) { l=read(),r=read(),ans=0; while(ans<(sum=T.Query(root[l-1],root[r],1,R,ans+1))) ans=sum; printf("%d\n",ans+1); } return 0; }