(WC2016模拟十八)【BZOJ4299】[CodeChef]FRBSUM

咕了若干天我终于来补坑了qwq

HINT

$1leq N,Mleq 10^5$

$1leq sum A_ileq 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
",ans); 
49     }
50     return 0;
51 }
原文地址:https://www.cnblogs.com/dcdcbigbig/p/9777240.html