(WC2016模拟十八)【BZOJ4299】[CodeChef]FRBSUM
咕了若干天我终于来补坑了qwq
HINT
$1\leq N,M\leq 10^5$
$1\leq \sum A_i\leq 10^9$
题解:
虽然场上做出来了但还是觉得好神啊!
假设当前集合能凑出$[1,max]$这些数,此时再加入一个数$x$:
1.若$x<=max+1$,则必定能继续凑出$[max+1,max+x]$这些数,新的$max=max+x$;
2.若$x>max+1$,则$max+1$这个数必定凑不出来,也就会成为当前的forbiddennum。
那么开一颗主席树,每次查询求出区间$[L,R]$中值在$[1,max+1]$中的数的和来更新$max$,直到$max+1$凑不出来为止;
这样子做每次$max$至少翻倍,因此每次查询至多更新$logn$次,总的时间复杂度就是$O(nlog^2n)$
ps:本题跟[LOJ2174]【FJOI2016】神秘数 为同一题意
代码:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 1000000000
8 #define eps 1e-9
9 using namespace std;
10 typedef long long ll;
11 struct node{
12 int v,ls,rs;
13 }t[7000001];
14 int n,m,l,r,tot=0,ans,tmp,num[100001],rts[100001];
15 void build(int &u,int k,int l,int r,int v){
16 u=++tot;
17 t[u].v=t[k].v+v;
18 t[u].ls=t[k].ls;
19 t[u].rs=t[k].rs;
20 if(l==r)return;
21 int mid=(l+r)/2;
22 if(v<=mid)build(t[u].ls,t[k].ls,l,mid,v);
23 else build(t[u].rs,t[k].rs,mid+1,r,v);
24 }
25 int query(int u,int k,int l,int r,int v){
26 if(l==r){
27 return t[k].v-t[u].v;
28 }
29 int mid=(l+r)/2;
30 if(v<=mid)return query(t[u].ls,t[k].ls,l,mid,v);
31 else return query(t[u].rs,t[k].rs,mid+1,r,v)+(t[t[k].ls].v-t[t[u].ls].v);
32 }
33 int main(){
34 scanf("%d",&n);
35 for(int i=1;i<=n;i++){
36 scanf("%d",&num[i]);
37 build(rts[i],rts[i-1],1,inf,num[i]);
38 }
39 scanf("%d",&m);
40 for(int i=1;i<=m;i++){
41 scanf("%d%d",&l,&r);
42 tmp=query(rts[l-1],rts[r],1,inf,1);
43 ans=1;
44 while(ans<=tmp){
45 ans=tmp+1;
46 tmp=query(rts[l-1],rts[r],1,inf,ans);
47 }
48 printf("%d\n",ans);
49 }
50 return 0;
51 }