hdu 3893 Wow! Such Sequence!

多校第三场,除了最水的一个模拟题,唯一会做的题目。但是比赛时一直超时超到死。问了a掉的同学才知道应该怎么写。

这道题目,是线段树,线段树的区间更新。

超时的思路:延时标记为某段区间是否需要算斐波那契。在x==3 时,打标记,不暂时求斐波那契,在查询或者更新单点的时候,如果之前要求做斐波那契,就解斐波那契。结果,不断的超时,超时。

在问了通过的同学的想法时,才知道,他们的延时标记为 在某段区间,是否需要求解斐波那契。但是,在 x == 3 也就是算斐波那契的那个操作时,进行 打标记以及解标记。换句话说,在 单点更新以及查询的时候,与这个延时标记无关。

以下是ac的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 400000
#define LL __int64
LL sum[maxn],col[maxn],f[111];
void init()//求解斐波那契数列
{
    f[0] = 1;
    f[1] = 1;
    for(int i = 2; i <= 92; i++)
    {
        f[i] = f[i-1] + f[i-2];
    }
}
LL change(LL num)//求解那个最接近的斐波那契数,因为个数比较小,所以直接暴力找了
{
    if(num<=1)return 1;
    LL minn = num;
    int temi = 92;
    for(int i = 2; i <= 92; i++)
    {
        LL tem = num - f[i];
        if(tem < 0) tem = - tem ;
        if(tem<minn)
        {
            minn = tem;
            temi = i ;
        }
        else break;
    }
    return f[temi];
}
void pushupSum(int rt)//线段树节点向上更新
{
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void pushupCol(int rt)//延时标记向上更新
{
    col[rt] = col[rt<<1] + col[rt<<1|1];
}
void update(int l,int r,int rt,int L,int R)//在算x==3时用到,进行区间的求解斐波那契的更新
{
    //如果该区间里每个数都是斐波那契,那么就不需要再求解斐波那契了,因为一个离斐波那契最近的数就是他自己
   if(col[rt] == r-l+1)return ;
   if(l==r)//如果该点不是斐波那契,那么进行标记并且求解
   {
       sum[rt] = change(sum[rt]);
       col[rt] = 1;
       return ;
   }
   int m = (l+r)>>1;
   if(m>=L)update(lson,L,R);
   if(m<R)update(rson,L,R);
   pushupCol(rt);
   pushupSum(rt);
}
LL query(int l,int r,int rt,int L,int R)//查询L R 区间里的和
{
    if(l>=L && r<=R )
    {
        return sum[rt];
    }
    int m = (l+r)>>1;
    LL an = 0;
    if(m>=L) an += query(lson,L,R);
    if(m<R)  an += query(rson,L,R);
    return an;
    pushupSum(rt);
}
void updateOne(int l,int r,int rt,int p,int num)//单点更新,在p位置加上num
{
    if(l==r)
    {
        col[rt] = 0;//因为该数字有改动,所以把他的延时标记改为,该数不是斐波那契
        sum[rt] += num ;
        return ;
    }
    int m = (l+r)>>1;
    if(m>=p)updateOne(lson,p,num);
    else if(m<p)updateOne(rson,p,num);
    pushupCol(rt);
    pushupSum(rt);
}
int main()
{
    int n,m,i,j,k,x,y,z;
    init();
    while(scanf("%d%d",&n,&m)!=-1)
    {
        memset(sum,0,sizeof(sum));
        memset(col,0,sizeof(col));
        while(m--)
        {
            scanf("%d%d%d",&x,&y,&z);
            if(x == 1)
            {
                updateOne(1,n,1,y,z);
            }
            else if(x == 2)
            {
                LL ans = query(1,n,1,y,z);
                printf("%I64d\n",ans);
            }
            else if(x == 3)
            {
                update(1,n,1,y,z);
            }
        }
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值