HDU 4893 - Wow! Such Sequence!(线段树)

题意:给定 n 个数的序列(1 <= n <= 100000,且初始均为 0),m 个操作(1 <= m <= 100000),操作共分三种:

1、将第 k 个数加 d;

2、求 l 到 r 区间和;

3、将 l 到 r 区间内的数,各自变为距离各自最近的斐波那契数(如果有两个数一样近,则取小的斐波那契数).

 

有区间求和区间修改还有点修改,很明显的一个线段树的题;

先将斐波那契数打表,然后每次查找时用 lower_bound 二分查找;

需要一个 sum 数组用来求和,写两个 update 函数分别为某个点数值增加以及区间修改成斐波那契;

为了防止超时,还需要增加一个“判断区间是否已经成为斐波那契数”的判断数组.

代码如下:

#pragma comment(linker, "/STACK:102400000, 102400000")
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)
#define pr(x) cout << #x << " : " << x << "   "
#define prln(x) cout << #x << " : " << x << endl
#define Min(a, b) a < b ? a : b
#define Max(a, b) a < b ? b : a
typedef long long ll;
typedef unsigned long long llu;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const ll LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const double pi = acos(-1.0);
const double EPS = 1e-8;
const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1};
const ll MOD = 1e9 + 7;
using namespace std;

#define NDEBUG
#include<cassert>
const int MAXN = 75 + 10;
const int MAXT = 100000 + 10;

ll fib[MAXN << 2];

void init(){
    fib[0] = 1;  fib[1] = 2;
    for(int i = 2; i < MAXN; ++i)  fib[i] = fib[i - 1] + fib[i - 2];
}

ll sum[MAXT << 2];
bool flag[MAXT << 2];

ll getfib(ll value){
    int lur = lower_bound(fib, fib + MAXN, value) - fib;
    ll one = abs(fib[lur] - value);
    ll two = lur > 0 ? abs(fib[lur - 1] - value) : one;
    if(one != two)  return one < two ? fib[lur] : fib[lur - 1];
    return lur > 0 ? fib[lur - 1] : fib[lur];
}

void PushUp(int lur){
    sum[lur] = sum[lur << 1] + sum[lur << 1 | 1];
    flag[lur] = flag[lur << 1] & flag[lur << 1 | 1];
}

void Update(int lur, int x, int l, int r, int id){
    if(l == r){
        sum[id] += x;
        flag[id] = false;
        return;
    }
    int mid = (l + r) >> 1;
    if(lur <= mid)  Update(lur, x, l, mid, id << 1);
    else  Update(lur, x, mid + 1, r, id << 1 | 1);
    PushUp(id);
}

void Update2(int L, int R, int l, int r, int id){
    if(flag[id])  return;
    if(l == r){
        sum[id] = getfib(sum[id]);
        flag[id] = true;
        return;
    }
    int mid = (l + r) >> 1;
    if(L <= mid)  Update2(L, R, l, mid, id << 1);
    if(mid < R)  Update2(L, R, mid + 1, r, id << 1 | 1);
    PushUp(id);
}

ll Query(int L, int R, int l, int r, int id){
    if(L <= l && r <= R){
        return sum[id];
    }
    int mid = (l + r) >> 1;
    ll ans = 0;
    if(L <= mid)  ans += Query(L, R, l, mid, id << 1);
    if(mid < R)  ans += Query(L, R, mid + 1, r, id << 1 | 1);
    return ans;
}

int main(){
    init();
    int n, m;
    while(scanf("%d%d", &n, &m) == 2){
        memset(sum, 0, sizeof sum);
        memset(flag, false, sizeof flag);
        while(m--){
            int o;  scanf("%d", &o);
            if(o == 1){
                int k;  int d;
                scanf("%d%d", &k, &d);
                Update(k, d, 1, n, 1);
            }
            else if(o == 2){
                int l, r;
                scanf("%d%d", &l, &r);
                printf("%I64d\n", Query(l, r, 1, n, 1));
            }
            else{
                int l, r;
                scanf("%d%d", &l, &r);
                Update2(l, r, 1, n, 1);
            }
        }
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/tyty-TianTengtt/p/6048295.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值