HDU 4893 Wow! Such Sequence!

http://acm.hdu.edu.cn/showproblem.php?pid=4893

题意就是 完成线段树的几种高端操作
操作如下:
1。 单点修改
2。 区间求和,并输出结果
3。 区间修改。PS: 这里要求把L~R区间内的所有值都变为最接近的那个斐波那契数0 0
这里我说下操作3吧,操作1和2 基础操作。

在这里,我们运用一种 叫做伴随树的东西,即每次线段树操作时 操作2课线段树,第一颗 就是正常的线段树,第二颗是 维护每个节点最接近的斐波那契数的值。 之后在设置一个标记数组,记录每个节点是否被覆盖。如果没有覆盖则覆盖。之后向下传标记。
具体看看代码

#include <bits/stdc++.h>
#define mme(i,j) memset(i,j,sizeof(i))
#define maxs 2002020
using namespace std;
long long fib[220];
long long seg[maxs],seg2[maxs];
bool flag[maxs];


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

void pushUp(int rt)
{
    seg[rt]=seg[rt<<1]+seg[rt<<1|1];
    seg2[rt]=seg2[rt<<1]+seg2[rt<<1|1];
}

void pushDown(int rt) {

    if(flag[rt]){

        flag[ rt<<1 ] = flag[ rt<<1|1 ] =1;
        seg[ rt<<1 ]  = seg2[ rt<<1 ];
        seg[ rt<<1|1 ] = seg2[ rt<<1|1 ];
        flag[rt]=0;
    }
}

long long getfib(long long x){

    int pos = lower_bound(fib,fib+105,x)-fib;
    if( pos == 0 )
        return 1;
    return abs( fib[pos]-x ) >= abs( x-fib[pos-1] ) ? fib[pos-1]:fib[pos];
}

void build(int l,int r,int rt)
{
    if(l==r)
    {
        seg[rt]=0;
        seg2[rt]=1;
        flag[rt]=0;
        return;
    }
    else{
        int m=( l + r )>>1;
        build( l , m , rt<<1 );
        build( m + 1 , r , rt<<1|1 );
        pushUp( rt );
    }
}

void updatepos(int p,int k,int l,int r,int rt){

    if(l==r){
        seg[rt]+=k;
        seg2[rt]=getfib(seg[rt]);
        flag[rt]=0;
        return;
    }
    pushDown(rt);
    int m=(l+r)>>1;

    if( p<=m ) updatepos(p,k,l,m,rt<<1);
    else       updatepos(p,k,m+1,r,rt<<1|1);
    pushUp(rt);
}

long long ans=0;

void updateseg(int al,int ar,int l,int r,int rt)
{
    if(al<=l && ar>=r){
        seg[rt]=seg2[rt];
        flag[rt]=1;
        return;
    }
    pushDown(rt);

    int m=(l+r)>>1;
    if(al<=m)
        updateseg(al,ar,l,m,rt<<1);
    if(m<ar)
        updateseg(al,ar,m+1,r,rt<<1|1);
    pushUp(rt);
}

void query(int al,int ar,int l,int r,int rt) {

    if( al <= l && ar >= r ){
        if(flag[rt])
            ans+=seg2[rt];
        else
            ans+=seg[rt];
        return;
    }
    pushDown(rt);
    int m = (l+r)>>1;
    if(al<=m)
        query(al,ar,l,m,rt<<1);
    if(m<ar)
        query(al,ar,m+1,r,rt<<1|1);
}

int main()
{
    int n,m;
    setfib();
    while(~scanf("%d%d",&n,&m)){
        mme(seg,0);
        mme(seg2,0);
        mme(flag,0);
        build(1,n,1);
        int op,x,y;
        while(m--){


            scanf("%d%d%d",&op,&x,&y);
            if(op==1)
                updatepos(x,y,1,n,1);
            else if( op == 2){
                ans=0;
                query(x,y,1,n,1);
                cout<<ans<<endl;
            }
            else if(op==3)
                updateseg(x,y,1,n,1);
        }
    }
    return 0;
}


/*
1 1
2 1 1
5 4
1 1 7
1 3 17
3 2 4
2 1 5

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值