题目链接:HDU 4893 Wow! Such Sequence !
用线段树比较明显,其中一个更新是将一个区间中的每个值变成和他最近的斐波那契数,这里有个小技巧。就是第一次变化后如再次询问,最近斐波那契数就是其本身,所以不需要再次更新。
AC代码:
#include<stdio.h>
#include<set>
#define int64 __int64
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
int64 f[10000];
const int maxn=200000;
set<int64> ss;
struct node
{
int64 l,r,laz;
int64 sum;
int64 mid()
{
return (l+r)/2;
}
};
struct node tree[maxn<<2];
void getf()//斐波那契打表。
{
int i;
f[0]=1,f[1]=1;
ss.insert(f[0]);
ss.insert(f[1]);
for(i=2;i<=73;i++)
{
f[i]=f[i-1]+f[i-2];
ss.insert(f[i]);
}
}
void PushUp(int64 rt)
{
if(tree[rt<<1].laz && tree[rt<<1|1].laz) //将标记向上推
tree[rt].laz=1;
else
tree[rt].laz=0;
tree[rt].sum=tree[rt<<1].sum+tree[rt<<1|1].sum;
}
void build(int64 l,int64 r,int64 rt)
{
tree[rt].l=l;
tree[rt].r=r;
tree[rt].laz=0;
if(tree[rt].l==tree[rt].r)
{
tree[rt].sum=0;
return ;
}
int64 m=tree[rt].mid();
build(lson);
build(rson);
PushUp(rt);
}
void updata(int64 p,int64 add,int64 rt)
{
if(tree[rt].l==tree[rt].r)
{
tree[rt].laz=0;//加过后标记更新
tree[rt].sum+=add;
return ;
}
int64 m=tree[rt].mid();
if(p<=m)
updata(p,add,rt<<1);
else
updata(p,add,rt<<1|1);
PushUp(rt);
}
void updata2(int64 L,int64 R,int64 rt)
{
if(tree[rt].laz==1) //其子节点都被更新过。
return ;
if(tree[rt].l==tree[rt].r)
{
tree[rt].laz=1;
int64 l,r;
set<int64>::iterator it1,it2;
it2=it1=ss.lower_bound(tree[rt].sum);
l=*it2;
if(it1!=ss.begin())
it1--;
r=*it1;
tree[rt].sum=(tree[rt].sum-*it1)> ((*it2)-tree[rt].sum)?l:r;
return ;
}
int64 m=tree[rt].mid();
if(R<=m)
updata2(L,R,rt<<1);
else if(L>m)
updata2(L,R,rt<<1|1);
else
{
updata2(L,R,rt<<1);
updata2(L,R,rt<<1|1);
}
PushUp(rt);
}
int64 query(int64 L,int64 R,int64 rt)
{
if(L<=tree[rt].l && tree[rt].r<=R)
{
return tree[rt].sum;
}
int64 m=tree[rt].mid();
int64 ret=0;
if(R<=m)
ret+=query(L,R,rt<<1);
else if(L>m)
ret+=query(L,R,rt<<1|1);
else
{
ret+=query(L,R,rt<<1);
ret+=query(L,R,rt<<1|1);
}
return ret;
}
int main()
{
int64 a,b,c;
int64 op,i;
int64 n,m;
ss.clear();
getf();
while(scanf("%I64d %I64d",&n,&m)!=EOF)
{
build(1,n,1);
while(m--)
{
scanf("%I64d",&op);
if(op==2)
{
scanf("%I64d %I64d",&a,&b);
printf("%I64d\n",query(a,b,1));
}
else if(op==1)
{
scanf("%I64d %I64d",&a,&b);
updata(a,b,1);
}
else if(op==3)//f
{
scanf("%I64d %I64d",&a,&b);
updata2(a,b,1);
}
}
}
return 0;
}