线段树 + 区间更新: HDU 4893 Wow! Such Sequence!

Wow! Such Sequence!

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2234    Accepted Submission(s): 657

Problem Description

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 F0 = 1,F1 = 1,Fibonacci number Fn is defined as Fn = Fn - 1 + Fn - 2 for n ≥ 2.

Nearest Fibonacci number of number x means the smallest Fn where |Fn - 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| < 231, 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.

Sample Input

1 1
2 1 1
5 4
1 1 7
1 3 17
3 2 4
2 1 5

Sample Output

0
22

Author

Fudan University

Source

2014 Multi-University Training Contest 3


【题目分析】

这题相比于裸的线段树区间更新有了一些难度。
我们在每个结点中设一个fib,表示离sum最近的fibnacci数,每次区间更新时,就将sum的值更新为fib。fib的值只有在单点更新的过程中才会改变,也就是说当sum值改变的时候fib才改变,因为当sum变为fib后,离sum最近的fibnacci数还是fib值。

lazy----记录该点以下的孩子结点是否需要更新。

我用long long ,然后用了%lld输入,不知道杭电不支持%lld,debug了半天,TLE了20多次,后来改%lld为%I64d就过了,哭死QAQ...


//Memory   Time
//  K      MS
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<iomanip>
#include<string>
#include<climits>
#include<cmath>
#define MAX 100010
#define LL long long
using namespace std;
LL n,m;
LL ans;
LL f[60];

struct Tree
{
    LL l,r;
    LL sum,fib;
    bool lazy;
};
Tree tree[MAX*3];

LL Find(LL x)
{
    if(x<=0)return 1;
    LL ldis,rdis;
    for(int i=0;i<59;++i)
    {
        if(f[i]<=x&&f[i+1]>=x)
        {
            ldis=x-f[i];
            rdis=f[i+1]-x;
            return ldis<=rdis?f[i]:f[i+1];
        }
    }
}

void pushup(LL x)
{
    LL tmp=x<<1;
    tree[x].sum=tree[tmp].sum+tree[tmp+1].sum;
    tree[x].fib=tree[tmp].fib+tree[tmp+1].fib;
}

void pushdown(LL x)
{
    if(!tree[x].lazy)return;
    tree[x].lazy=0;
    if(tree[x].l==tree[x].r)return;
    LL tmp=x<<1;
    tree[tmp].lazy=tree[tmp+1].lazy=1;
    tree[tmp].sum=tree[tmp].fib;
    tree[tmp+1].sum=tree[tmp+1].fib;
}

void build(LL l,LL r,LL x)
{
    tree[x].l=l,tree[x].r=r;
    tree[x].sum=0,tree[x].fib=1,tree[x].lazy=0;
    if(l==r)return;
    LL tmp=x<<1;
    LL mid=(l+r)>>1;
    build(l,mid,tmp);
    build(mid+1,r,tmp+1);
    pushup(x);
}

void add(LL x,LL k,LL num)
{
    if(tree[x].l==tree[x].r)
    {
        tree[x].sum+=num;
        tree[x].fib=Find(tree[x].sum);
        return;
    }
    if(tree[x].lazy)
        pushdown(x);
    LL tmp=x<<1;
    LL mid=(tree[x].l+tree[x].r)>>1;
    if(k<=mid)
        add(tmp,k,num);
    else if(k>mid)
        add(tmp+1,k,num);
    pushup(x);
}

void change(LL l,LL r,LL x)
{
    if(r<tree[x].l||l>tree[x].r)return;
    if(l<=tree[x].l&&r>=tree[x].r)
    {
        tree[x].sum=tree[x].fib;
        tree[x].lazy=1;
        return;
    }
    if(tree[x].lazy)pushdown(x);
    LL tmp=x<<1;
    LL mid=(tree[x].l+tree[x].r)>>1;
    if(r<=mid)
        change(l,r,tmp);
    else if(l>mid)
        change(l,r,tmp+1);
    else
    {
        change(l,mid,tmp);
        change(mid+1,r,tmp+1);
    }
    pushup(x);
}

void query(LL l,LL r,LL x)
{
    if(r<tree[x].l||l>tree[x].r)return;
    if(l<=tree[x].l&&r>=tree[x].r)
    {
        ans+=tree[x].sum;
        return;
    }
    if(tree[x].lazy)
        pushdown(x);
    LL tmp=x<<1;
    LL mid=(tree[x].l+tree[x].r)>>1;
    if(r<=mid)
        query(l,r,tmp);
    else if(l>mid)
        query(l,r,tmp+1);
    else
    {
        query(l,mid,tmp);
        query(mid+1,r,tmp+1);
    }
    pushup(x);
}

int main()
{
//    freopen("cin.txt","r",stdin);
//    freopen("cout.txt","w",stdout);
    f[0]=f[1]=1;
    for(int i=2;i<60;++i) f[i]=f[i-1]+f[i-2];
    while(scanf("%I64d %I64d",&n,&m)!=EOF)
    {
        build(1,n,1);
        LL a,b,c;
        while(m--)
        {
            scanf("%I64d %I64d %I64d",&a,&b,&c);
            if(a==1)
                add(1,b,c);
            else if(a==2)
            {
                ans=0;
                query(b,c,1);
                printf("%I64d\n",ans);
            }
            else
                change(b,c,1);
        }
    }
    return 0;
}

  

线段树 + 区间更新: HDU 4893 Wow! Such Sequence!

时间: 2024-08-10 21:30:31

线段树 + 区间更新: HDU 4893 Wow! Such Sequence!的相关文章

线段树 + 区间更新 ----- HDU 4902 : Nice boat

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 968    Accepted Submission(s): 441 Problem Description There is an old country and the king fell in love with a devil. The devil alw

hdu 4893 Wow! Such Sequence!(线段树功能:单点更新,区间更新相邻较小斐波那契数)

转载请注明出处:http://blog.csdn.net/u012860063?viewmode=contents 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 --------------------------------------------------------------------------------------------------------------------------------------------

HDU 4893 Wow! Such Sequence! (线段树)

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 838    Accepted Submission(s): 245 Problem Description Recently, Doge got a funny birthday present from his new friend, Prot

hdu 4893 Wow! Such Sequence!(线段树)

题目链接:hdu 4983 Wow! Such Sequence! 题目大意:就是三种操作 1 k d, 修改k的为值增加d 2 l r, 查询l到r的区间和 3 l r, 间l到r区间上的所以数变成最近的斐波那契数,相等的话取向下取. 解题思路:线段树,对于每个节点新增一个bool表示该节点以下的位置是否都是斐波那契数. #include <cstdio> #include <cstring> #include <cstdlib> #include <algor

HDU 4893 Wow! Such Sequence! 水线段树

思路: 线段树走起.. 写完这题就退役T^T 单点更新的时候直接找到这个点的最近fib,然后维护当前和 和 fib的和 #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> #include<algorithm> #include<queue> #include<map> #include<set> #include&l

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

HDU 5023 A Corrupt Mayor&#39;s Performance Art 线段树区间更新+状态压缩

Link:  http://acm.hdu.edu.cn/showproblem.php?pid=5023 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <string> 7 #include <cmath> 8 using namesp

HDU 5023 A Corrupt Mayor&#39;s Performance Art(线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 解题报告:一面墙长度为n,有N个单元,每个单元编号从1到n,墙的初始的颜色是2,一共有30种颜色,有两种操作: P a b c  把区间a到b涂成c颜色 Q a b 查询区间a到b的颜色 线段树区间更新,每个节点保存的信息有,存储颜色的c,30种颜色可以压缩到一个int型里面存储,然后还有一个tot,表示这个区间一共有多少种颜色. 对于P操作,依次往下寻找,找要更新的区间,找到要更新的区间之前

HDU 4902 Nice boat(线段树 区间更新)

Nice boat 大意:给你一个区间,每次可以进行两种操作,1:把区间中的数全都变成x  2:把区间中大于x的数变成gcd(a[i], x),最后输出序列. 思路:线段树成段更行,用num数组的叶子存储数据,节点当作lazy来使用. 1 #include <stdio.h> 2 const int maxn = 100005; 3 4 int num[maxn<<2]; 5 6 int gcd(int a, int b){ 7 return b?gcd(b, a%b):a; 8