zoukankan      html  css  js  c++  java
  • BZOJ4408: [Fjoi 2016]神秘数【主席树好题】

    Description

    一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数。例如S={1,1,1,4,13},

    1 = 1

    2 = 1+1

    3 = 1+1+1

    4 = 4

    5 = 4+1

    6 = 4+1+1

    7 = 4+1+1+1

    8无法表示为集合S的子集的和,故集合S的神秘数为8。

    现给定n个正整数a[1]..a[n],m个询问,每次询问给定一个区间l,r,求由a[l],a[l+1],…,a[r]所构成的可重复数字集合的神秘数。

    Input

    第一行一个整数n,表示数字个数。
    第二行n个整数,从1编号。
    第三行一个整数m,表示询问个数。
    以下m行,每行一对整数l,r,表示一个询问。

    Output

    对于每个询问,输出一行对应的答案。

    Sample Input

    5
    1 2 4 9 10
    5
    1 1
    1 2
    1 3
    1 4
    1 5

    Sample Output

    2
    4
    8
    8
    8

    HINT

    对于100%的数据点,n,m <= 100000,∑a[i] <= 10^9


    思路

    这是一个不套路的主席树题...真的是好题

    首先发现一个性质,如果当前可以凑出来的区间是([1,x])

    那么如果有一个y需要被加进集合中

    如果(yle x + 1),那么新的可以表示出来的区间一定是([1,x+y])

    否则的话(x+1)一定不能被表示出来

    但是这样需要按大小顺序考虑每一个数

    所以就可以用主席数可持久化一下

    然后每次因为在([1,x+1])之间的数都可以被计入贡献

    所以可以直接求一个前缀sum就可以了

    每次就比较一下,如果不能更新答案或者没有合法答案就可以退出了

    复杂度很迷我不会证明


    //Author: dream_maker
    #include<bits/stdc++.h>
    using namespace std;
    //----------------------------------------------
    //typename
    typedef long long ll;
    //convenient for
    #define fu(a, b, c) for (int a = b; a <= c; ++a)
    #define fd(a, b, c) for (int a = b; a >= c; --a)
    #define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
    //inf of different typename
    const int INF_of_int = 1e9;
    const ll INF_of_ll = 1e18;
    //fast read and write
    template <typename T>
    void Read(T &x) {
      bool w = 1;x = 0;
      char c = getchar();
      while (!isdigit(c) && c != '-') c = getchar();
      if (c == '-') w = 0, c = getchar();
      while (isdigit(c)) {
        x = (x<<1) + (x<<3) + c -'0';
        c = getchar();
      }
      if (!w) x = -x;
    }
    template <typename T>
    void Write(T x) {
      if (x < 0) {
        putchar('-');
        x = -x; 
      }
      if (x > 9) Write(x / 10);
      putchar(x % 10 + '0');
    }
    //----------------------------------------------
    const int N = 1e5 + 10;
    const int M = 2e6 + 10;
    int rt[N], ls[M], rs[M], tot = 0;
    ll sum[M];
    void build(int &t, int l, int r) {
      t = ++tot;
      ls[t] = rs[t] = sum[t] = 0;
      if (l == r) return;
      int mid = (l + r) >> 1;
      build(ls[t], l, mid);
      build(rs[t], mid + 1, r);
    }
    void insert(int &t, int last, int l, int r, int pos, int vl) {
      t = ++tot;
      ls[t] = ls[last];
      rs[t] = rs[last];
      sum[t] = sum[last] + vl;
      if (l == r) return;
      int mid = (l + r) >> 1;
      if (pos <= mid) insert(ls[t], ls[last], l, mid, pos, vl);
      else insert(rs[t], rs[last], mid + 1, r, pos, vl);
    }
    ll query(int t, int last, int l, int r, int pos) {
      if (l == r) return sum[t] - sum[last];
      int mid = (l + r) >> 1;
      if (pos <= mid) return query(ls[t], ls[last], l, mid, pos);
      else return sum[ls[t]] - sum[ls[last]] + query(rs[t], rs[last], mid + 1, r, pos);
    }
    int n, m, q, a[N], b[N], pre[N];
    int find_pow(int vl) {
      int l = 1, r = m, res = 0;
      while (l <= r) {
        int mid = (l + r) >> 1;
        if (pre[mid] <= vl) res = mid, l = mid + 1;
        else r = mid - 1;
      }
      return res;
    }
    int main() {
      //freopen("input.txt", "r", stdin);
      Read(n);
      fu(i, 1, n) {
        Read(a[i]);
        pre[i] = a[i];
      }
      sort(pre + 1, pre + n + 1);
      m = unique(pre + 1, pre + n + 1) - pre - 1;
      pre[m + 1] = INF_of_int;
      build(rt[0], 1, m);
      fu(i, 1, n) {
        b[i] = lower_bound(pre + 1, pre + m + 1, a[i]) - pre;
        insert(rt[i], rt[i - 1], 1, m, b[i], a[i]);
      }
      Read(q);
      while (q--) {
        int l, r; Read(l), Read(r);
        ll now = 0;
        while (1) {
          int pos = find_pow(now + 1);
          if (!pos) {++now; break;}
          int s = query(rt[r], rt[l - 1], 1, m, pos);
          if (s <= now) {
            ++now;
            break;
          }
          now = s;
        }
        Write(now), putchar('
    ');
      }
      return 0;
    }
    
  • 相关阅读:
    对于数据库表排他更新的理解
    小学数学题
    胜败兵家事不期
    ORACLE外键约束(FORIGEN KEY)
    spring客户端jsp与服务端交互方法
    nodejs学习笔记package.json
    关于viewport
    dl,dt,dd的用法
    304-NOT MODIFIED
    $(document).ready()和 window.onload的区别
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9863688.html
Copyright © 2011-2022 走看看