给定一个序列,现有3种操作:
1. 查询区间[l,r]的元素的和。
2. 将区间[l,r]元素置为最近的Fibonacci数
3. 将第x个元素加上d
线段树,维护区间和,区间都变成Fibonacci数之后的和,以及是否进了变为Fibonacci数的懒操作标记即可。
最开始因为把第3个操作看成了把第x个元素置成d..调了好久...
#include <cstdio>
#include <set>
using namespace std;
struct Node {
long long v,vv;
bool flag;
Node *ls,*rs;
void down() {
if (!flag) return;
if (ls) {
ls->v=ls->vv;
ls->flag=true;
}
if (rs) {
rs->v=rs->vv;
rs->flag=true;
}
flag=false;
}
void repair() {
v=ls->v+rs->v;
vv=ls->vv+rs->vv;
}
};
Node a[200100];
Node *ap,*root;
int n,m;
set <long long> c;
long long nearstFib(long long x) {
if (x<=1) return 1;
set<long long>::iterator tmp=c.lower_bound(x);
long long y=*tmp;
tmp--;
long long z=*tmp;
if (y-x<x-z) return y;
return z;
}
Node *maketree(int l,int r) {
Node *ans=ap++;
if (l==r) {
ans->ls=ans->rs=NULL;
ans->v=0;
ans->vv=1;
} else {
int t=(l+r)/2;
ans->ls=maketree(l,t);
ans->rs=maketree(t+1,r);
ans->repair();
}
ans->flag=false;
return ans;
}
void set1(Node *from,int l,int r,int i,int x) {
if (l==r) {
from->flag=false;
from->v+=x;
from->vv=nearstFib(from->v);
} else {
from->down();
int t=(l+r)/2;
if (i<=t) {
set1(from->ls,l,t,i,x);
} else {
set1(from->rs,t+1,r,i,x);
}
from->repair();
}
}
long long get(Node *from,int l,int r,int ll,int rr) {
if (l==ll&&r==rr) {
return from->v;
}
from->down();
int t=(l+r)/2;
if (rr<=t) {
return get(from->ls,l,t,ll,rr);
} else if (ll>t) {
return get(from->rs,t+1,r,ll,rr);
} else {
return get(from->ls,l,t,ll,t)+get(from->rs,t+1,r,t+1,rr);
}
}
void set2(Node *from,int l,int r,int ll,int rr) {
if (l==ll&&r==rr) {
from->flag=true;
from->v=from->vv;
} else {
from->down();
int t=(l+r)/2;
if (rr<=t) {
set2(from->ls,l,t,ll,rr);
} else if (ll>t) {
set2(from->rs,t+1,r,ll,rr);
} else {
set2(from->ls,l,t,ll,t);
set2(from->rs,t+1,r,t+1,rr);
}
from->repair();
}
}
int main() {
long long x,y,z;
int i;
x=y=1;
while (y<1ll<<62) {
c.insert(y);
z=y;
y+=x;
x=z;
}
while (scanf("%d%d",&n,&m)!=EOF) {
ap=a;
root=maketree(1,n);
for (i=0;i<m;i++) {
int k,l,r;
scanf("%d%d%d",&k,&l,&r);
if (k==1) {
set1(root,1,n,l,r);
} else if (k==2) {
printf("%lld\n",get(root,1,n,l,r));
} else if (k==3) {
set2(root,1,n,l,r);
}
}
}
return 0;
}