HDU4893 线段树 修改为最近的Fib

来源:互联网 发布:linux给mysql增加用户 编辑:程序博客网 时间:2024/04/29 13:06

传送门:点击打开链接

Wow! Such Sequence!

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


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 12 1 15 41 1 71 3 173 2 42 1 5
 

Sample Output
022
 

Author
Fudan University
 

Source
2014 Multi-University Training Contest 3 


题意:

1 把第K个点加上D;

2 把区间[l,r]里的数变为离它最近的斐波那契数(这个fib数最小,且这个fib减这个数的绝对值也最小)

3 询问[l,r]区间内的和

思路:

维护两个sum。sum1存放当前区间的和,sum2存放当前区间所有数变成fib之后的和。这样,进行覆盖的时候,被覆盖的区间直接sum1=sum2就行了。

详细操作见代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>using namespace std;#define LL __int64struct node{    int l,r;    LL sum1,sum2;    bool c;}tree[400005];LL F[105];void pushup(int id){    tree[id].sum1=tree[id<<1].sum1+tree[id<<1|1].sum1;    tree[id].sum2=tree[id<<1].sum2+tree[id<<1|1].sum2;}void pushdown(int id){    if(tree[id].c)    {        tree[id<<1].c=tree[id<<1|1].c=1;        tree[id<<1].sum1=tree[id<<1].sum2;        tree[id<<1|1].sum1=tree[id<<1|1].sum2;        tree[id].c=0;    }}void build(int id,int l,int r){    tree[id].l=l;    tree[id].r=r;    tree[id].c=0;    if(l==r)    {        tree[id].sum1=0;        tree[id].sum2=1;    }    else    {        int mid=(l+r)>>1;        build(id<<1,l,mid);        build(id<<1|1,mid+1,r);        pushup(id);    }}LL near(LL x){    int p=lower_bound(F,F+90,x)-F;    if(p&&abs(x-F[p-1])<=abs(F[p]-x)) return F[p-1];    else return F[p];}void add(int id,int pos,int x){    if(tree[id].l==tree[id].r)    {        tree[id].sum1+=x;        tree[id].sum2=near(tree[id].sum1);    }    else    {        pushdown(id);        int mid=(tree[id].l+tree[id].r)>>1;        if(pos<=mid) add(id<<1,pos,x);        else add(id<<1|1,pos,x);        pushup(id);    }}void op(int id,int l,int r){    if(l<=tree[id].l&&tree[id].r<=r)    {        tree[id].sum1=tree[id].sum2;        tree[id].c=1;    }    else    {        pushdown(id);        int mid=(tree[id].l+tree[id].r)>>1;        if(l<=mid) op(id<<1,l,r);        if(mid<r) op(id<<1|1,l,r);        pushup(id);    }}LL sum(int id,int l,int r){    if(l<=tree[id].l&&tree[id].r<=r) return tree[id].sum1;    else    {        pushdown(id);        int mid=(tree[id].l+tree[id].r)>>1;        LL res=0;        if(l<=mid) res+=sum(id<<1,l,r);        if(mid<r) res+=sum(id<<1|1,l,r);        return res;    }}int main(){    F[0]=1;    F[1]=1;    for(int i=2;i<=90;i++) F[i]=F[i-1]+F[i-2];    int n,m;    while(~scanf("%d %d",&n,&m))    {        build(1,1,n);        while(m--)        {            int x,y,z;            scanf("%d %d %d",&x,&y,&z);            if(x==1) add(1,y,z);            else if(x==2)                printf("%I64d\n",sum(1,y,z));            else op(1,y,z);        }    }    return 0;}


0 0