hdu 4893——Wow! Such Sequence!

题意:有三种操作,1是将第k个数加d,2是查询从l到r内的数的和,3是将从l到r内的所有数改成与其最近的斐波那契数。

思路:线段树。维护两个和,第一个是这一个区间内的数的和,第二个是如果将这个区间内的数改成斐波那契数以后的和。

错误:移位符号的优先级特别低,必须加括号,要不就错了在这里re了一次。基本每次都会忘。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;

typedef long long ll;
const int maxn=300005;

ll Fib(ll n)
{
    ll i=1;
    ll j=1;
    ll tmp=n+1;
    while(abs(j-n)<tmp)
    {
        tmp=abs(j-n);
        ll t=i+j;
        i=j;
        j=t;
    }
    return i;
}

ll nsum[maxn];
ll fsum[maxn];
int status[maxn];

void build(int o,int L,int R)
{
    status[o]=-1;
    nsum[o]=0;
    fsum[o]=1;
    int mid=L+((R-L)>>1);
    if(L<R){
        build(o*2,L,mid);
        build(o*2+1,mid+1,R);
        fsum[o]=fsum[o*2]+fsum[o*2+1];
    }
}

void maintain(int o,int L,int R)
{
    int lc=o*2,rc=o*2+1;
    if(R>L){
        nsum[o]=nsum[lc]+nsum[rc];
        fsum[o]=fsum[lc]+fsum[rc];
        if(status[lc]+status[rc]==2)status[o]=1;
        else if(status[lc]+status[rc]==-2)status[o]=-1;
        else status[o]=0;
    }
}

void pushdown(int o)
{
    int lc=o*2;int rc=o*2+1;
    if(status[o]==1){
        status[o*2]=1;
        status[o*2+1]=1;
    }
    else if(status[o]==-1){
        status[o*2]=-1;
        status[o*2+1]=-1;
    }
    status[o]=0;
}
int id,add;
void update1(int o,int L,int R)
{
    if(L == R){
        if(status[o] == 1){
            nsum[o] = fsum[o];
        }
        nsum[o] += add;
        status[o] =- 1;
        fsum[o] = Fib(nsum[o]);
        if(fsum[o] == nsum[o])status[o] = 1;
        return;
    }

    int mid = L + ((R-L) >> 1);
    pushdown(o);
    if(id <= mid){
        update1(o*2, L, mid);
        maintain(o*2, L, mid);
    } else {
        update1(o*2+1, mid+1, R);
        maintain(o*2+1, mid+1, R);
    }
    maintain(o, L, R);
}

int yl,yr;
void update2(int o,int L,int R)
{
    if(yl<=L && yr>=R && status[o]==1){
        if(L!=R)
        {
            nsum[o] = fsum[o*2] + fsum[o*2+1];
        } else {
            nsum[o] = Fib(nsum[o]);
            fsum[o] = nsum[o];
        }
    } else if (L == R){
        status[o] = 1;
        nsum[o] = Fib(nsum[o]);
        fsum[o] = nsum[o];
    } else {
        pushdown(o);
        int mid = L + ((R-L)>>1);
        if(yl <= mid){
            update2(o*2, L, mid);
            maintain(o*2, L, mid);
        }
        if(yr>mid){
            update2(o*2+1, mid+1, R);
            maintain(o*2, mid+1, R);
        }
    }
    maintain(o, L, R);
}

ll query(int o,int L,int R)
{
    ll ans=0;
    if(yl<=L && yr>=R){
        if(status[o] == 1)return fsum[o];
        else return nsum[o];
    } else {
        int mid = L + ((R-L) >> 1);
        if(yl <= mid)ans += query(o*2, L, mid);
        if(yr > mid)ans += query(o*2+1, mid+1, R);
    }
    return ans;
}

int main()
{
//    freopen("data.txt","r",stdin);
    int n,m;
    while(scanf("%d%d",&n,&m) != EOF){
        build(1, 1, n);
        for(int i=0; i<m; ++i){
            int q;
            int l,r;
            scanf("%d%d%d",&q,&l,&r);
            if (q == 1) {
                id = l;
                add = r;
                update1(1, 1, n);
            } else if (q == 3){
                yl = l;yr = r;
                update2(1, 1, n);
            } else {
                yl = l,yr = r;
                ll ans = query(1, 1, n);
                printf("%I64d\n",ans);
            }
        }
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值