[[FJOI2016]神秘数][主席树]

明白之后 5min 就写好了…自闭…

这题的题意是问你 \([L,R]\) 区间的数字不能构成的数字的最小值…

首先考虑 如果 \([1,x]\) 可以被表示

那么加入一个 \(a_i\) 显然 \([1,x+a_i]\) 都可以被表示

有什么好办法呢

当然有 \(O(q * \sum_{i\in[L,R]}{a_i}*[R-L+1])\)

区间求和问题啥的考虑主席树,首先我不会证明复杂度,是因为我菜/kk

还是一样的套路 讨论 \([1,x]\)

对于区间求 \(\sum_{i\in[L,R]}[a_i<=ans]\)
\([ans\)初值是1\(]\)

显然此时 \([1,ans-1]\) 都可以表示出来 所以考虑扩大区间使得这个\(res = \sum_{i\in[L,R]}[a_i<=ans]\)

如果值比 \(ans\) 小肯定是不可以构成 \(ans+1\) 的 所以无需扩展…

#include<bits/stdc++.h>

using ll = long long ;
using namespace std ;

int read() {
  int x = 0 , f = 1 ; char c = getchar() ;
  while(c < '0' || c > '9') { if(c == '-') f = -1 ; c = getchar() ; }
  while(c >= '0' && c <= '9') { x = (x << 1) + (x << 3) + (c & 15) ; c = getchar() ; }
  return x * f ;
}

const int N = 1e5 + 10 ;
const int MAXN = N << 5 ;
const int INF = 1e9 ;
int n , a[N] , rt[N] , ls[MAXN] , rs[MAXN] , sum[MAXN] , cnt = 0 ;
void upd(int pre , int & o , int l , int r , int pos , int val) {
  ls[o = ++ cnt] = ls[pre] ; rs[o] = rs[pre] ; sum[o] = sum[pre] + val ;
  if(l == r) return ; int mid = l + r >> 1 ;
  if(pos <= mid) upd(ls[pre] , ls[o] , l , mid , pos , val) ;
  else upd(rs[pre] , rs[o] , mid + 1 , r , pos , val) ;
}
int query(int a , int b , int l , int r , int L , int R) {
  if(a <= l && r <= b) return (sum[R] - sum[L]) ;
  int mid = l + r >> 1 , ans = 0 ;
  if(a <= mid) ans += query(a , b , l , mid , ls[L] , ls[R]) ;
  if(b > mid) ans += query(a , b , mid + 1 , r , rs[L] , rs[R]) ;
  return ans ;
}
signed main() {
  n = read() ;
  for(int i = 1 ; i <= n ; i ++) a[i] = read() ;
  for(int i = 1 ; i <= n ; i ++) upd(rt[i - 1] , rt[i] , 1 , INF , a[i] , a[i]) ;
  int m = read() ;
  while(m --) {
    int L = read() , R = read() , ans = 1 ;
    while(1) {
      int res = query(1 , ans , 1 , INF , rt[L - 1] , rt[R]) ;
      if(res >= ans) ans = res + 1 ;
      else break ;
    }
    printf("%d\n" , ans) ;
  }
  return 0 ;
}

猜你喜欢

转载自www.cnblogs.com/Isaunoya/p/12001116.html