您的位置:首页 > 产品设计 > UI/UE

A - Wow! Such Sequence!——线段树+lazy

2015-01-23 19:22 471 查看
####

线段树+lazy操作

       Recently, Doge got a funny birthday present from his new friend, Protein Tiger from St. Beeze College. No, not cactuses. It's a mysterious blackbox. 

After some research, Doge found that the box is maintaining a sequence an of n numbers internally, initially all numbers are zero, and there are THREE "operations": 

1.Add d to the k-th number of the sequence. 

2.Query the sum of ai where l ≤ i ≤ r. 

3.Change ai to the nearest Fibonacci number, where l ≤ i ≤ r. 

4.Play sound "Chee-rio!", a bit useless. 

Let F 0 = 1,F 1 = 1,Fibonacci number Fn is defined as F n = F n - 1 + F n - 2 for n ≥ 2. 

Nearest Fibonacci number of number x means the smallest Fn where |F n - x| is also smallest. 

Doge doesn't believe the machine could respond each request in less than 10ms. Help Doge figure out the reason.

 
Input

Input contains several test cases, please process till EOF. 

For each test case, there will be one line containing two integers n, m. 

Next m lines, each line indicates a query: 

1 k d - "add" 

2 l r - "query sum" 

3 l r - "change to nearest Fibonacci" 

1 ≤ n ≤ 100000, 1 ≤ m ≤ 100000, |d| < 2 31, all queries will be valid.

 Output

For each Type 2 ("query sum") operation, output one line containing an integer represent the answer of this query.

 

[b]Sample Input
[/b]



1 1
2 1 1
5 4
1 1 7
1 3 17
3 2 4
2 1 5 Sample Output
022


#题意:这是一个线段树,给你n个节点,m次操作,每个节点的初始值为0,;当输入为1的时候对应位置节点加p。当输入为2的时候 ,查询区间总和。当输入为3的时候,节点替换为与他差值最小的FIB数列的值,差值相同的取小的那个:

题解:

这里我们维护两个值,sum1,sum2,前者表示当前值,后者表示与他对应的FIB数列的值。其他的基本上就是和线段树一样。但是注意这里我们要进行lazy操作不然不T则W;

注意这里我们要用—int64,不然要错;

#include<string.h>

#include<iostream>

#include<string>

#include<algorithm>

#include<math.h>

#include<stdio.h>

#include<map>

using namespace std;

#define mx 100009

__int64   a[mx];

struct node

{

    __int64    le,ri,sum1;

    __int64    sum2;

    __int64    flag;

} tree[mx*4];

__int64 find1(__int64  val)

{

    __int64   ss=lower_bound(a,a+90,val)-a;   //查找fib数列里的对应值
    if(ss==0) return 1;
    if(a[ss]!=val)
    {
        if((a[ss]-val)>=(val-a[ss-1]))
            return a[ss-1];
        else
            return a[ss];
    }
    else return a[ss];

}
void pushup(__int64   id)
{
    tree[id].sum1=tree[id*2].sum1+tree[id*2+1].sum1;
    tree[id].sum2=tree[id*2].sum2+tree[id*2+1].sum2;
}

void  pushdown(__int64  id)
{
    if(tree[id].flag)
    {
        tree[id*2].sum1=tree[id*2].sum2;
        tree[id*2+1].sum1=tree[id*2+1].sum2;
        tree[id].flag=0;
        tree[id*2+1].flag=tree[id*2].flag=1;
    }
}

void buildtree(__int64 id,__int64  l,__int64  r)
{

    tree[id].le=l;
    tree[id].ri=r;
    tree[id].flag=0;
    if(l==r)
    {
        tree[id].sum2=1;
        tree[id].sum1=0;
        return ;
    }
    __int64   mid=(l+r)/2;
    buildtree(id*2,l,mid);
    buildtree(id*2+1,mid+1,r);
    pushup(id);
}

void update1(__int64  id,__int64  pos,__int64  val)
{

    if(tree[id].le==tree[id].ri)
    {
        tree[id].sum1+=val;
        tree[id].sum2=find1(tree[id].sum1);
        return ;
    }
      pushdown(id);   //注意这里我们要向下更新,不然到时再累加操作的时候值没有更新的话就是错的,自己在想一下就想通了,主要是要考虑区间
    __int64   mid=(tree[id].le+tree[id].ri)/2;
    if(pos<=mid)
        update1(id*2,pos,val);
    else update1(id*2+1,pos,val);
    pushup(id);
}

void update2(__int64 id,__int64  l,__int64  r)
{
    if(tree[id].le>=l&&tree[id].ri<=r)
    {

        tree[id].sum1=tree[id].sum2;
        tree[id].flag=1;
        return ;
    }
    pushdown(id);   //这里向下更新
    __int64    mid=(tree[id].le+tree[id].ri)/2;
    if(l<=mid)
        update2(id*2,l,r);
    if(r>mid) update2(id*2+1,l,r);
    pushup(id);
}

__int64   ans;
void  ask(__int64  id,__int64  l,__int64  r)
{
    if(tree[id].le>=l&&tree[id].ri<=r)
    {
        ans+=tree[id].sum1;
        return;
    }
      pushdown(id);              //这里也是,我们要考虑区间,W了多次看了别人的代码,才发现这个错误,哎,太弱了
    __int64  mid=(tree[id].le+tree[id].ri)/2;
    if(l<=mid)
        ask(id*2,l,r);
    if(mid<r)
        ask(id*2+1,l,r);
}
int main()
{
    __int64   n,m,i,j;
    __int64   l,r;
    __int64   gg;
    while(scanf("%I64d %I64d",&n,&m)!=EOF)
    {
        buildtree(1,1,n);
        a[1]=a[0]=1;
        for(i=2; i<=90; i++)
        {
            a[i]=a[i-1]+a[i-2];
        }
        while(m--)
        {
            scanf("%I64d %I64d %I64d",&gg,&l,&r);
            if(gg==1)
            {

                update1(1,l,r);
            }
            else if(gg==2)
            {
                ans=0;
                ask(1,l,r);
                printf("%I64d\n",ans);
            }
            else if(gg==3)
            {

                update2(1,l,r);
            }
        }
    }
      return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: