Codeforces 633H Fibonacci-ish II【線段樹】
阿新 • • 發佈:2018-11-09
題目大意
給你一個序列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; }