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;
}


 
  

猜你喜欢

转载自blog.csdn.net/qq_37451344/article/details/80769514