本题为一道线段树应用题,但区间更新略有不同。
同时维护两颗线段树,一颗存储原有数串及其区间和,另一颗存储原有数串的最近费波拉契数及这些费波拉契数的区间和。
每一次区间更新不必更新至最底层,直接将该要更新的区间和替换为费波拉契树相应位置的区间和。
AC代码:
#include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <assert.h> #include <algorithm> #define MAX 1234567890 #define MIN -1234567890 #define eps 1e-8 using namespace std; const int maxn = 100100; long long fibo[61]; long long sum[maxn<<2], rep[maxn<<2]; bool col[maxn<<2]; long long search_fibo(long long x, int l, int r) { if(x <= 0) return 1; for(int i = 1; i < 60; i++) { if(fibo[i] <= x && fibo[i+1] >= x) { long long ldis = x - fibo[i]; long long rdis = fibo[i+1] - x; return ldis <= rdis ? fibo[i] : fibo[i+1]; } } } void push_down(int rt) { if(col[rt]) { col[rt<<1] = col[rt<<1|1] = col[rt]; sum[rt<<1] = rep[rt<<1]; sum[rt<<1|1] = rep[rt<<1|1]; col[rt] = false; } } void build(int l, int r, int rt) { if(l == r) { rep[rt] = 1; return ; } int m = (l + r) >> 1; build(l, m, rt<<1); build(m+1, r, rt<<1|1); rep[rt] = rep[rt<<1] + rep[rt<<1|1]; } void update_point(int p, int add, int l, int r, int rt) { if(l == r) { sum[rt] += (long long)add; // cout << "sum[" << rt << "]: " << sum[rt] << endl; rep[rt] = search_fibo(sum[rt], 0, 60); // cout << "rep[" << rt << "]: " << rep[rt] << endl; return ; } push_down(rt); int m = (l + r) >> 1; if(p <= m) update_point(p, add, l, m, rt<<1); else update_point(p, add, m+1, r, rt<<1|1); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; rep[rt] = rep[rt<<1] + rep[rt<<1|1]; } void update_interval(int L, int R, int l, int r, int rt) { if(L <= l && R >= r) { col[rt] = true; sum[rt] = rep[rt]; return ; } push_down(rt); int m = (l + r) >> 1; if(L <= m) update_interval(L, R, l, m, rt<<1); if(R > m) update_interval(L, R, m+1, r, rt<<1|1); sum[rt] = sum[rt<<1] + sum[rt<<1|1]; } long long query(int L, int R, int l, int r, int rt) { if(L <= l && R >= r) return sum[rt]; push_down(rt); int m = (l + r) >> 1; long long ret = 0; if(L <= m) ret += query(L, R, l, m, rt<<1); if(R > m) ret += query(L, R, m+1, r, rt<<1|1); return ret; } int main() { #ifdef BellWind freopen("4893.in", "r", stdin); #endif // BellWind fibo[0] = fibo[1] = 1; for(int i = 2; i <= 60; i++) fibo[i] = fibo[i-1] + fibo[i-2]; int n, m; while(~scanf("%d%d", &n, &m)) { memset(sum, 0, sizeof(sum)); memset(col, 0, sizeof(col)); build(1, n, 1); while(m--) { int op, a, b; scanf("%d%d%d", &op, &a, &b); if(op == 2) printf("%I64d\n", query(a, b, 1, n, 1)); if(op == 1) update_point(a, b, 1, n, 1); if(op == 3) update_interval(a, b, 1, n, 1); } } return 0; }