• Codeforces 633H Fibonacci-ish II【线段树】


    LINK


    题目大意

    给你一个序列a,Q次询问,每次询问([l,r])
    ([l,r])的数排序去重,得到序列b,f是斐波那契数列
    (sum_{b=1}^{len} b_if_i)

    思路

    发现单次如果加入和减去一个数
    只需要把这个数的贡献加上/减去,然后把大于他的数斐波那契数的下标++/--
    这个东西如果可以维护就可以完成单次加入个删除了

    那么就可以用莫队来把询问离线处理
    然后考虑加入一个数或者删除一个数
    先离散化,用线段树维护起来

    每个区间直接维护这个区间的答案
    因为线段树需要累加标记,所以直接考虑把下表标加上k的贡献??

    这东西需要一个结论(f_{n+k}=f_{n}f_{k+1}+f_{n-1}{k})
    发现(sum_{b=1}^{len} b_if_{i+k}=sum_{b=1}^{len}b_i*f_if_{k+1}+sum_{b=1}^{len}b_i*f_{i-1}f_{k})
    发现只需要区间只需要维护两个值(sum_{b=1}^{len}b_if_i)(sum_{b=1}^{len}b_if_{i-1})就可以了
    那么(sum_{b=1}^{len}b_if_{i-1}),咋维护?
    (sum_{b=1}^{len}b_if_{i-1}=sum_{b=1}^{len}b_if_if_k+sum_{b=1}^{len}f_{i-1}f_{k-1})

    因为有减法操作,所以还需要处理斐波那契数列下标是负数的情况,加上偏移量逆推就行了

    然后还需要一些卡常技巧
    比如在单点加上贡献的时候,每次向左走就可以把右边区间的下标加上
    然后可以线段树非递归卡卡常。。。。

    能不取模就别取模


    //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 = 3e4 + 10;
    int n, q, Mod;
    int cnt[N] = {0}, pre[N], tot = 0, a[N];
    int ans[N], f[N << 1];
    struct Query {
      int l, r, id;
    } Q[N];
    int block[N], siz_of_block;
    bool cmp(Query a, Query b) {
      if (block[a.l] == block[b.l]) return a.r < b.r;
      return a.l < b.l;
    }
    int add(int a, int b) {
      return (a += b) >= Mod ? a - Mod : a;
    }
    int sub(int a, int b) {
      return (a -= b) < 0 ? a + Mod : a;
    }
    int mul(int a, int b) {
      return 1ll * a * b % Mod;
    }
    void init() {
      f[N] = 0, f[N + 1] = 1;
      fu(i, N + 2, (N << 1) - 1) f[i] = add(f[i - 2], f[i - 1]);
      fd(i, N - 1, 1) f[i] = sub(f[i + 2], f[i + 1]);
    }
    #define LD (t << 1)
    #define RD (t << 1 | 1)
    int val1[N << 2], val2[N << 2], tag[N << 2];
    void pushup(int t) {
      val1[t] = add(val1[LD], val1[RD]);
      val2[t] = add(val2[LD], val2[RD]);
    }
    void pushnow(int t, int vl) {
      int lastval1 = val1[t];
      int lastval2 = val2[t];
      tag[t] += vl;
      val1[t] = (lastval1 * f[N + vl + 1] + lastval2 * f[N + vl]) % Mod;
      val2[t] = (lastval1 * f[N + vl] + lastval2 * f[N + vl - 1]) % Mod;
    }
    void pushdown(int t) {
      if (tag[t]) {
        pushnow(LD, tag[t]);
        pushnow(RD, tag[t]);
        tag[t] = 0;
      }
    }
    void insert(int t, int l, int r, int pos) {
      while (l < r) {
        pushdown(t);
        int mid = (l + r) >> 1;
        if (pos <= mid) {
          pushnow(RD, 1);
          t = LD, r = mid;
        } else {
          t = RD;
          l = mid + 1;
        }
      }
      val1[t] = mul(pre[l], f[N + tag[t] + 1]);
      val2[t] = mul(pre[l], f[N + tag[t]]);
      while (t >>= 1) pushup(t);
    }
    void remove(int t, int l, int r, int pos) {
      while (l < r) {
        pushdown(t);
        int mid = (l + r) >> 1;
        if (pos <= mid) {
          pushnow(RD, -1);
          t = LD, r = mid;
        } else {
          t = RD;
          l = mid + 1;
        }
      }
      val1[t] = val2[t] = 0;
      while (t >>= 1) pushup(t);
    }
    void insert(int pos) {
      if (++cnt[pos] == 1) insert(1, 1, tot, pos);
    }
    void remove(int pos) {
      if (--cnt[pos] == 0) remove(1, 1, tot, pos);
    }
    int main() {
      //freopen("input.txt", "r", stdin);
      Read(n), Read(Mod);
      init();
      fu(i, 1, n) {
        Read(a[i]);
        pre[i] = a[i]; 
      }
      sort(pre + 1, pre + n + 1);
      tot = unique(pre + 1, pre + n + 1) - pre - 1;
      fu(i, 1, n) a[i] = lower_bound(pre + 1, pre + tot + 1, a[i]) - pre;
      siz_of_block = sqrt(n);
      fu(i, 1, n) block[i] = (i - 1) / siz_of_block + 1;
      Read(q);
      fu(i, 1, q) Read(Q[i].l), Read(Q[i].r), Q[i].id = i;
      sort(Q + 1, Q + q + 1, cmp);
      int l = 1, r = 0;
      fu(i, 1, q) {
        while (r < Q[i].r) insert(a[++r]);
        while (r > Q[i].r) remove(a[r--]);
        while (l > Q[i].l) insert(a[--l]);
        while (l < Q[i].l) remove(a[l++]);
        ans[Q[i].id] = val1[1];
      }
      fu(i, 1, q) {
        Write(ans[i]);
        putchar('
    ');
      }
      return 0;
    }
    
  • 相关阅读:
    轻松搞定技术面系列 1——基础篇
    Java集合排序(看完秒懂)
    详解 jupyter notebook 集成 spark 环境安装
    Java——观察者模式实例
    Java——泛型(最易懂的方式讲解泛型)
    Linux目录
    Python目录
    Nginx入门与实战
    数组与链表
    图算法之——dijkstra算法
  • 原文地址:https://www.cnblogs.com/dream-maker-yk/p/9821366.html
Copyright © 2020-2023  润新知