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('\n');
  }
  return 0;
}
posted @ 2018-10-20 13:28  Dream_maker_yk  阅读(254)  评论(0编辑  收藏  举报