(bzoj4408)[FJOI2016]神秘数(可持久化线段树)
(bzoj4408)[FJOI2016]神秘数(可持久化线段树)
对于一个区间的数,排序之后从左到右每一个数扫
如果扫到某个数a时已经证明了前面的数能表示[1,x],那么分情况:
a>x+1,不能继续表示下去,答案就是x+1
否则表示区间变为[1,x+a]。
用主席树上二分优化这个过程。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 const int N=100069; 5 const int orz_phy=998244353; 6 #define cint const int 7 template<typename TP> inline void read(TP &_t) 8 { 9 TP _r=0,_f=1;char _c=getchar(); 10 while(_c<'0'||_c>'9'){if(_c=='-')_f=-1;_c=getchar();} 11 while(_c>='0'&&_c<='9'){_r=_r*10+_c-'0';_c=getchar();} 12 _t=_r*_f; 13 } 14 int n,a[N]; 15 16 int rt[N]; 17 struct chairman 18 { 19 int s[N*88],son[N*88][2],ct; 20 void ins(cint pp,int &px,cint pl,cint pr,cint x) 21 { 22 px=++ct,s[px]=s[pp]+x; 23 if(pl==pr) return; 24 int mi=(pl+pr)>>1; 25 if(x<=mi) son[px][1]=son[pp][1],ins(son[pp][0],son[px][0],pl,mi,x); 26 else son[px][0]=son[pp][0],ins(son[pp][1],son[px][1],mi+1,pr,x); 27 } 28 int query(cint pp,cint px,cint pl,cint pr,cint l,cint r) 29 { 30 if(l<=pl&&pr<=r) return s[px]-s[pp]; 31 int mi=(pl+pr)>>1; 32 int ret=0; 33 if(l<=mi) ret+=query(son[pp][0],son[px][0],pl,mi,l,r); 34 if(r>mi) ret+=query(son[pp][1],son[px][1],mi+1,pr,l,r); 35 return ret; 36 } 37 }ct; 38 39 int T,li,ri; 40 signed main() 41 { 42 read(n); 43 for(int i=1;i<=n;i++) read(a[i]),ct.ins(rt[i-1],rt[i],1,1000000000,a[i]); 44 read(T); 45 while(T--) 46 { 47 read(li),read(ri); 48 int ans=1,tmp=0; 49 while(orz_phy) 50 { 51 if((tmp=ct.query(rt[li-1],rt[ri],1,1000000000,1,ans))>=ans) ans=tmp+1; 52 else break; 53 } 54 printf("%d\n",ans); 55 } 56 return 0; 57 }