HDU 4893 Wow!Such a sequence!(线段树+斐波那契二分)

Wow! Such Sequence!

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


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 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.
 

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
 

Recommend
We have carefully selected several similar problems for you:   6297  6296  6295  6294  6293
#include <queue>
#include <iostream>
#include<cstring>
#include<stdio.h>
#define maxn 100004
using namespace std;
__int64 n,m;
int type,x,y;
__int64 table[100],area[100];
typedef long long LL;
/*
玄学,,怎么也过不了。。。。
题目大意是给定n个数的序列,
初始化为零,
然后提供三种修改方式,
单点加法,查询区间和,修改区间使区间中每个数变成它的最近斐波那契数。
主要输出在查询区间和。

对于二分查找斐波那契的做法,
可以直接二分查找上界然后比较两边的数字。
我的做法是对于每两个相邻的数相加除二,
得到的序列是对应每个斐波那契数的映射区间,,
即原位置和下一位置的数的左开右闭区间便是映射的区间。
*/
struct node
{
    int l,r;
    long long sum;
    long long fib;
    int flagsum;
    node()
    {
        fib=0;
        flagsum=0;
        l=r=sum=0;
    }
};

__int64  binsearch(__int64 x)
{
    int l=1,r=99;
    while(r-l>1)
    {
        int mid=(r+l)>>1;
        if(area[mid]<x) l=mid;
        else if(area[mid]>=x) r=mid;
    }
    return table[l];
}

node seq[maxn*5];
__int64 num[maxn];

void pushup(int rt)
{
    if(seq[rt].l==seq[rt].r)   return ;
    seq[rt].sum=seq[rt<<1].sum+seq[rt<<1|1].sum;
    seq[rt].fib=seq[rt<<1].fib+seq[rt<<1|1].fib;
}

void pushdown(int rt)
{
     if(seq[rt].flagsum==1)
     {
         if(seq[rt].l==seq[rt].r)
            seq[rt].sum=seq[rt].fib;
         else
         {
             seq[rt<<1].flagsum=1;
             seq[rt<<1].sum=seq[rt<<1].fib;
             seq[rt<<1|1].flagsum=1;
             seq[rt<<1|1].sum=seq[rt<<1].fib;
         }
         seq[rt].flagsum=0;
     }
}

void build(int l,int r,int rt)
{
    seq[rt].l=l;
    seq[rt].r=r;
    if(l==r)
    {
        seq[rt].fib=1;
        seq[rt].sum=num[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}

void update1(int p,int rt,int v )
{
    if(seq[rt].l==p&&seq[rt].r==p)
    {
        seq[rt].sum+=v;
        seq[rt].fib=binsearch( seq[rt].sum );
        num[p]+=v;
        return ;
    }
    int mid=(seq[rt].l+seq[rt].r)>>1;
    if(mid>=p)
        update1(p,rt<<1,v);
    else if(mid<p)
        update1(p,rt<<1|1,v);
    pushup(rt);
}

void update2(int l,int r,int rt)
{
    if(seq[rt].l>=l&&seq[rt].r<=r)
    {
        seq[rt].flagsum=1;
        seq[rt].sum=seq[rt].fib;
        return ;
    }
    pushdown(rt);
    int mid=(seq[rt].l+seq[rt].r)>>1;
    if(l<=mid) update2(l,r,rt<<1);
    if(r>mid) update2(l,r,rt<<1|1);
    pushup(rt);
}

__int64  query(int l,int r,int rt)
{
    if(l<=seq[rt].l&&seq[rt].r<=r)
        return seq[rt].sum;
    __int64 ans=0;
    pushdown(rt);
    int mid=(seq[rt].l+seq[rt].r)>>1;
    if(mid>=l)  ans+=query(l,r,rt<<1);
    if(mid<r)  ans+=query(l,r,rt<<1|1);
    return ans;
}

int main()
{
    ios::sync_with_stdio(false);
    table[0]=1,table[1]=1;
    for(int i=2;i<100;i++) table[i]=table[i-1]+table[i-2];
    for(int i=1;i<100;i++) area[i]=(table[i]+table[i-1])/2;


    //int x;while(cin>>x) cout<<binsearch(x)<<endl;
    while( ~scanf("%d%d",&n,&m) )
    {
        build(1,n,1);
        //memset(num,0,sizeof(num));
        for(int i=0;i<m;i++)
        {
            scanf("%d%d%d",&type,&x,&y);
            if(type==1)  update1(x,1,y);
            else if(type==3)  update2(x,y,1);
            else printf("%I64d\n",query(x,y,1));
            //for(int i=1;i<=n;i++) cout<<num[i]<<" ";
            //cout<<endl;
        }
    }
    return 0;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值