1. 程式人生 > >【HDU 4893 多校聯合】 Wow! Such Sequence!【線段樹】

【HDU 4893 多校聯合】 Wow! Such Sequence!【線段樹】

題意在這裡就不說了。直接說思路,這是一道裸的線段樹,每個節點儲存區間的和sum以及區間變成斐波那契數的和fs。然後就是簡單點修改和區間修改的事了。

詳細見程式碼

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define N 100006
#define mid (l+r>>1)
#define lc (d<<1)
#define rc (d<<1|1)
#define ll long long
ll fb[1005]; struct Tr{ ll sum, fs; int lz; }tr[N<<2]; void Push(int d) { tr[d].sum = tr[lc].sum+tr[rc].sum; tr[d].fs = tr[lc].fs+tr[rc].fs; } void build(int d, int l, int r) { if (l == r) { tr[d].sum = 0, tr[d].fs = 1; tr[d].lz = 0; return; } tr[
d].lz = 0; build(lc, l, mid); build(rc, mid+1, r); Push(d); } void lazy(int d, int l, int r) { if (tr[d].lz) { tr[lc].lz = 1, tr[lc].sum = tr[lc].fs; tr[rc].lz = 1, tr[rc].sum = tr[rc].fs; tr[d].lz = 0; } } ll cal(ll a) { int f = 0, r = 90, m; while (
f < r) { m = (f+r)/2; //cout << f << " " << m << " " << r << " " << fb[m] << endl; if (fb[m] < a) f = m+1; else r = m; } // printf("[%lld %d %lld]\n", a, f, fb[f]); if (f == 0) return fb[f]; ll tm = fb[f]-a; if (tm < a-fb[f-1]) return fb[f]; return fb[f-1]; } void add(int d, int l, int r, int pos, int ad) { if (l == r && l == pos) { //if(tr[d].lz == 1) tr[d].sum = cal(tr[d].sum); tr[d].sum += ad; tr[d].fs = cal(tr[d].sum); tr[d].lz = 0; return; } lazy(d, l, r); if (pos <= mid) add(lc, l, mid, pos, ad); else add(rc, mid+1, r, pos, ad); Push(d); } ll query(int d, int l, int r, int L, int R) { if (l == L && r == R) { return tr[d].sum; } lazy(d, l, r); if (R <= mid) return query(lc, l, mid, L, R); else if (L > mid) return query(rc, mid+1, r, L, R); else return query(lc, l, mid, L, mid)+query(rc, mid+1, r, mid+1, R); } void update(int d, int l, int r, int L, int R) { if (l == L && r == R) { tr[d].sum = tr[d].fs; tr[d].lz = 1; return; } lazy(d, l, r); if (R <= mid) update(lc, l, mid, L, R); else if (L > mid) update(rc, mid+1, r, L, R); else update(lc, l, mid, L, mid), update(rc, mid+1, r, mid+1, R); Push(d); } int main() { int n, m, i, j, q; memset(fb, 0, sizeof(fb)); fb[0] = 1, fb[1] = 2; for (i = 2;i < 91;i++) fb[i] = fb[i-1]+(ll)fb[i-2]; // for (i = 0;i < 91;i++) cout << fb[i] << endl; // cout<<cal(1000000000)<<endl; while (~scanf("%d%d", &n, &m)) { build(1, 1, n); while (m--) { scanf("%d", &q); scanf("%d%d", &i, &j); if (q == 1) { add(1, 1, n, i, j); }else if (q == 2) { cout << query(1, 1, n, i, j) << endl; }else { update(1, 1, n, i, j); } } } return 0; }