题意:
给你大小为n的序列,该序列的初始值为0,有3种操作
1.序列的第K个位置增加d
2.询问一段区间的和
3.将一段区间中得每一个数值都改为一个最小的fibonacci数,
且该fibonacci数与区间内对应的值距离最近。
解题思路:
可以用线段树来解决该问题,且线段树中得域:
lazy标记:表示当前某区间更新的标记
sum:用于求某段区间的和
lin;表示某段区间中的每一个值距离其最近的fibo的差值
所以当我们更新到某段区间时,我们要将该段的lazy = 1;
并要将sum+=lin,lin = 0;
注意:
要用__int64 。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define MAXN0 1<<64
#define l1(x) (x)<<1
#define l11(x) l1(x)|1
#define r1(x) (x)>>1
#define MAXN1 100001
typedef __int64 LL;
LL F[MAXN1];
int n,m;
struct TRnode{
int L,R;
int lazy;
LL sum;
LL lin;
};
LL min(LL aa,LL bb){
return aa<bb?aa:bb;
}
LL getbt(LL gx){
int l,r,mid;
l = 0;
r = 91;
while(l<r){
mid = r1(l+r);
if(F[mid]>=gx){
r = mid;
}
else{
l = mid+1;
}
}
LL tmp1,tmp2,tmp0;
if(l==0){
tmp0 = F[l] - gx;
if(tmp0<0)tmp0 = -tmp0;
tmp1 = F[l+1] - gx;
if(tmp1<0)tmp1 = -tmp1;
return tmp0<=tmp1?F[l]:F[l+1];
}
else if(l==91){
tmp0 = F[l] - gx;
if(tmp0<0)tmp0 = -tmp0;
tmp1 = F[l-1] - gx;
if(tmp1<0)tmp1 = -tmp1;
return tmp0<tmp1?F[l]:F[l-1];
}
else {
tmp0 = F[l-1] - gx;
if(tmp0<0)tmp0= -tmp0;
tmp1 = l-1;
for(int i=l;i<=l+1;++i){
tmp2 = F[i] - gx;
if(tmp2<0){
tmp2 = -tmp2;
}
if(tmp2<tmp0){
tmp1 = i;
tmp0 = tmp2;
}
}
return F[tmp1];
}
}
TRnode TR[MAXN1<<2];
void buildTR(int L,int R,int k){
TR[k].L = L;
TR[k].R = R;
TR[k].lazy = 0;
if(L==R){
TR[k].sum = 0;
TR[k].lin = 1;
return;
}
TR[k].sum = 0;
int mid = r1(L+R);
//TR[k].lin =
buildTR(L,mid,l1(k));
buildTR(mid+1,R,l11(k));
TR[k].lin = TR[l1(k)].lin + TR[l11(k)].lin;
}
void pd(int k,int k1,int k11){
TR[k1].lazy = TR[k11].lazy = TR[k].lazy;
TR[k1].sum = TR[k1].lin + TR[k1].sum;
TR[k11].sum = TR[k11].lin + TR[k11].sum;
TR[k1].lin = TR[k11].lin = 0;
TR[k].lazy = 0;
}
void pu(int k,int k1,int k11){
TR[k].lin = TR[k1].lin + TR[k11].lin;
TR[k].sum = TR[k1].sum + TR[k11].sum;
}
void update(int L,int R,int k,LL val,bool flag){
if(TR[k].L==L&&TR[k].R==R){
if(flag){
TR[k].lazy = 1;
TR[k].sum = TR[k].lin + TR[k].sum;
TR[k].lin = 0;
}
else {
if(TR[k].lazy){
TR[k].sum=TR[k].sum+TR[k].lin;
}
TR[k].sum+=val;
TR[k].lin = getbt(TR[k].sum) - TR[k].sum;
TR[k].lazy = 0;
//TR[k].sum +=val;
}
return;
}
if(TR[k].lazy){
pd(k,l1(k),l11(k));
}
int mid = r1(TR[k].L+TR[k].R);
if(mid>=R){
update(L,R,l1(k),val,flag);
}
else if(mid<L){
update(L,R,l11(k),val,flag);
}
else {
update(L,mid,l1(k),val,flag);
update(mid+1,R,l11(k),val,flag);
}
pu(k,l1(k),l11(k));
}
LL Query(int L,int R,int k){
if(TR[k].L==L&&TR[k].R==R){
return TR[k].sum;
}
if(TR[k].lazy){
pd(k,l1(k),l11(k));
}
int mid = r1(TR[k].L+TR[k].R);
if(mid>=R){
return Query(L, R, l1(k));
}
else if(mid<L){
return Query(L,R,l11(k));
}
else {
return Query(L,mid,l1(k))+Query(mid+1, R, l11(k));
}
}
int main(){
F[0] = 1;
F[1] = 1;
//freopen("/Users/gatsby/desktop/oo.txt", "w", stdout);
for(int i =2;i<=91;++i){
F[i] = F[i-1] + F[i-2];
//printf("%llu\n",F[i]);
}
int w;
int k,L,R;
LL d;
while(scanf("%d%d",&n,&m)!=EOF){
buildTR(1,n,1);
while(m--){
scanf("%d",&w);
if(w==1){
scanf("%d%I64d",&k,&d);
update(k,k,1,d,false);
}
else if(w==2){
scanf("%d%d",&L,&R);
LL ans = Query(L, R, 1);
printf("%I64d\n",ans);
}
else {
scanf("%d%d",&L,&R);
update(L,R,1,0,true);
}
}
}
return 0;
}