HDU 4893 线段树

比赛时太大意,斐波拉契数列开小了。

 

题目大意:1个序列,3种操作,改变序列某个数大小,将序列中连续的一段每个数都变成其最近的斐波拉契数,以及查询序列中某一段的数之和。

解题思路:维护add[]数组表示线段树中每一段的需要改变到斐波拉契数的总和即可,color[]表示该段是否需要改变成斐波拉契,而当需要改变成斐波拉契数时,直接将sum+=add。其余便是线段树基础操作。

 

复制代码
#include <cstdio>
#define T 1000005
#define N 100005
long long f[81],sum[T],add[T];
int l,r,p;
bool color[T];
void PushDown(int rt){
    if(color[rt]){
        color[rt]=0;
        color[rt*2]=color[rt*2+1]=1;
        sum[rt*2]+=add[rt*2];
        sum[rt*2+1]+=add[rt*2+1];
        add[rt*2]=0;
        add[rt*2+1]=0;
    }
}
void PushUp(int rt){
    sum[rt]=sum[rt*2]+sum[rt*2+1];
    add[rt]=add[rt*2]+add[rt*2+1];
}
void build(int l, int r, int rt){
    sum[rt]=0;
    color[rt]=0;
    if(l==r) add[rt]=1;
    if(l>=r) return;
    int m=(l+r)/2;
    build(l,m,rt*2);
    build(m+1,r,rt*2+1);
    PushUp(rt);
}
void update(int k, int d, int l, int r, int rt){
    if(l==r){
        color[rt]=0;
        sum[rt]+=d;
        if(sum[rt]<=0) add[rt]=1-sum[rt];
        else{
            for(int i=0; i<=64; i++)
                if(f[i]<=sum[rt]&&sum[rt]<f[i+1]){
                    if(sum[rt]-f[i]<=f[i+1]-sum[rt])
                        add[rt]=f[i]-sum[rt];
                    else 
                        add[rt]=f[i+1]-sum[rt];
                    break;
                }
        }
        return;
    }
    PushDown(rt);
    int m=(l+r)/2;
    if(k<=m) update(k,d,l,m,rt*2);
        else update(k,d,m+1,r,rt*2+1);
    PushUp(rt);
}
void change(int x, int y, int l, int r, int rt){
    if(x<=l&&y>=r){
        sum[rt]+=add[rt];
        add[rt]=0;
        color[rt]=1;
        return;
    }
    PushDown(rt);
    int m=(l+r)/2;
    if(x<=m&&!color[rt*2]) change(x,y,l,m,rt*2);
    if(y>m&&!color[rt*2+1]) change(x,y,m+1,r,rt*2+1);
    PushUp(rt);
}
long long query(int x, int y, int l, int r, int rt){
    if(x<=l&&y>=r) return sum[rt];
    PushDown(rt);
    int m=(l+r)/2;
    long long s=0;
    if(x<=m) s+=query(x,y,l,m,rt*2);
    if(y>m) s+=query(x,y,m+1,r,rt*2+1);
    PushUp(rt);
    return s;
}
int main()
{
    f[0]=f[1]=1;
    for(int i=2; i<=80; i++)
        f[i]=f[i-1]+f[i-2];
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        build(1,n,1);
        for(int i=0; i<m; i++){
            scanf("%d%d%d",&p,&l,&r);
            switch (p){
                case 1:
                    update(l,r,1,n,1);
                break;
                case 2:
                    printf("%I64d\n",query(l,r,1,n,1));
                break;
                case 3:
                    change(l,r,1,n,1);
                break;
            }
        }
    }
    return 0;
}
View Code
复制代码

 

posted @   Estimator  阅读(253)  评论(0编辑  收藏  举报
编辑推荐:
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
阅读排行:
· 为DeepSeek添加本地知识库
· 精选4款基于.NET开源、功能强大的通讯调试工具
· DeepSeek智能编程
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· [翻译] 为什么 Tracebit 用 C# 开发
点击右上角即可分享
微信分享提示