(bzoj4408)[FJOI2016]神秘数(可持久化线段树)

(bzoj4408)[FJOI2016]神秘数(可持久化线段树)

bzoj luogu

对于一个区间的数,排序之后从左到右每一个数扫

如果扫到某个数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 }
View Code
posted @ 2019-10-14 10:22  RikukiIX  阅读(125)  评论(0编辑  收藏  举报