http://acm.hdu.edu.cn/showproblem.php?pid=4893
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.
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.
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
解题思路:关键是命令3的处理,我们可以把每段序列最接近的Fibonacci数求出来,在线段树里存放两个值,一个是真实值,一个是最接近的Fibonacci值,在执行3操作时采用“延时标记”的方法为需要把真值变成Fibonacci值的区间标记下来,在查询的时候,加以判断。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN=999999;
LL ab(LL x)
{
if(x<0)
return -x;
return x;
}
LL fib[100];
void get_fib()
{
fib[1]=fib[0]=1;
for(int i=2;i<=90;i++)
fib[i]=fib[i-1]+fib[i-2];
}
LL near_fib(LL x)
{
int l=0,r=90,mid;
int ans=0;
while(l<=r)
{
mid=(l+r)/2;
if(fib[mid]>=x)
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
if(ans==0)
return 1;
if(ab(fib[ans-1]-x)<=ab(fib[ans]-x))
return fib[ans-1];
return fib[ans];
}
struct SegmentTree
{
struct Tree
{
int l,r;
LL sum;
LL f;
bool fg;
};
Tree tree[MAXN*4];
void push_down(int root)//向下维护至叶子节点,如果被标记了的话,我们就把其子节点全部标记,并且更新其sum值为f值,并同时解除本身的标记。
{ //如果没被标记,那么此函数不进行任何操作。
if(tree[root].fg)
{
if(tree[root].l!=tree[root].r)
tree[root<<1].fg=tree[root<<1|1].fg=true;
else
tree[root].sum=tree[root].f;
tree[root].fg=false;
}
}
void push_up(int root)//向上维护至根节点,如果该节点被标记返回f值,没被标记返回sum值
{
LL sum=0;
if(tree[root<<1].fg)
sum+=tree[root<<1].f;
else
sum+=tree[root<<1].sum;
if(tree[root<<1|1].fg)
sum+=tree[root<<1|1].f;
else
sum+=tree[root<<1|1].sum;
tree[root].sum=sum;
tree[root].f=tree[root<<1].f+tree[root<<1|1].f;
}
void build(int root,int l,int r)//构造线段树
{
tree[root].l=l;
tree[root].r=r;
tree[root].fg=false;
if(tree[root].l==tree[root].r)
{
tree[root].sum=0;
tree[root].f=1;
return;
}
int mid=(l+r)/2;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
push_up(root);
}
void update(int root,int pos,int val)
{
push_down(root);
if(tree[root].l==tree[root].r)
{
tree[root].sum+=val;
tree[root].f=near_fib(tree[root].sum);
//这里需要特别注意,在更新其真值的时候就把其对应的斐波那契数列数求出来放在f里面
return;
}
int mid=(tree[root].l+tree[root].r)/2;
if(pos<=mid)
update(root<<1,pos,val);
else
update(root<<1|1,pos,val);
push_up(root);//向上维护,把其祖先节点全部变为相应的更新后的值
}
void dfs(int root,int L,int R)//将要查询区间上的值改为标记过的,否则的话查询时是错误的。比如标记的(1,10)而查询的时候是(4,7)这一步dfs就凸显作用了
{
push_down(root);
if(L<=tree[root].l&&R>=tree[root].r)
{
if(tree[root].l!=tree[root].r)
push_up(root);
return;
}
int mid=(tree[root].l+tree[root].r)/2;
if(L<=mid)
dfs(root<<1,L,R);
if(R>mid)
dfs(root<<1|1,L,R);
push_up(root);
}
LL query(int root,int L,int R)
{
if(L<=tree[root].l&&R>=tree[root].r)
{
if(tree[root].fg)
return tree[root].f;
return tree[root].sum;
}
int mid=(tree[root].l+tree[root].r)/2;
LL ret=0;
if(L<=mid)
ret+=query(root<<1,L,R);
if(R>mid)
ret+=query(root<<1|1,L,R);
return ret;
}
void change(int root,int L,int R)
{
push_down(root);
if(L<=tree[root].l&&R>=tree[root].r)
{
tree[root].fg=true;
return;
}
int mid=(tree[root].l+tree[root].r)/2;
if(L<=mid)
change(root<<1,L,R);
if(R>mid)
change(root<<1|1,L,R);
push_up(root);
}
}tr;
int n,m;
int main()
{
get_fib();
while(~scanf("%d%d",&n,&m))
{
tr.build(1,1,n);
for(int i=0;i<m;i++)
{
int p,x,y;
scanf("%d%d%d",&p,&x,&y);
if(p==1)
{
tr.update(1,x,y);
}
else if(p==3)
{
tr.change(1,x,y);
}
else
{
tr.dfs(1,x,y);
LL ans=tr.query(1,x,y);
printf("%I64d\n",ans);
}
}
}
return 0;
}