题意:有三种操作,1是将第k个数加d,2是查询从l到r内的数的和,3是将从l到r内的所有数改成与其最近的斐波那契数。
思路:线段树。维护两个和,第一个是这一个区间内的数的和,第二个是如果将这个区间内的数改成斐波那契数以后的和。
错误:移位符号的优先级特别低,必须加括号,要不就错了在这里re了一次。基本每次都会忘。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=300005;
ll Fib(ll n)
{
ll i=1;
ll j=1;
ll tmp=n+1;
while(abs(j-n)<tmp)
{
tmp=abs(j-n);
ll t=i+j;
i=j;
j=t;
}
return i;
}
ll nsum[maxn];
ll fsum[maxn];
int status[maxn];
void build(int o,int L,int R)
{
status[o]=-1;
nsum[o]=0;
fsum[o]=1;
int mid=L+((R-L)>>1);
if(L<R){
build(o*2,L,mid);
build(o*2+1,mid+1,R);
fsum[o]=fsum[o*2]+fsum[o*2+1];
}
}
void maintain(int o,int L,int R)
{
int lc=o*2,rc=o*2+1;
if(R>L){
nsum[o]=nsum[lc]+nsum[rc];
fsum[o]=fsum[lc]+fsum[rc];
if(status[lc]+status[rc]==2)status[o]=1;
else if(status[lc]+status[rc]==-2)status[o]=-1;
else status[o]=0;
}
}
void pushdown(int o)
{
int lc=o*2;int rc=o*2+1;
if(status[o]==1){
status[o*2]=1;
status[o*2+1]=1;
}
else if(status[o]==-1){
status[o*2]=-1;
status[o*2+1]=-1;
}
status[o]=0;
}
int id,add;
void update1(int o,int L,int R)
{
if(L == R){
if(status[o] == 1){
nsum[o] = fsum[o];
}
nsum[o] += add;
status[o] =- 1;
fsum[o] = Fib(nsum[o]);
if(fsum[o] == nsum[o])status[o] = 1;
return;
}
int mid = L + ((R-L) >> 1);
pushdown(o);
if(id <= mid){
update1(o*2, L, mid);
maintain(o*2, L, mid);
} else {
update1(o*2+1, mid+1, R);
maintain(o*2+1, mid+1, R);
}
maintain(o, L, R);
}
int yl,yr;
void update2(int o,int L,int R)
{
if(yl<=L && yr>=R && status[o]==1){
if(L!=R)
{
nsum[o] = fsum[o*2] + fsum[o*2+1];
} else {
nsum[o] = Fib(nsum[o]);
fsum[o] = nsum[o];
}
} else if (L == R){
status[o] = 1;
nsum[o] = Fib(nsum[o]);
fsum[o] = nsum[o];
} else {
pushdown(o);
int mid = L + ((R-L)>>1);
if(yl <= mid){
update2(o*2, L, mid);
maintain(o*2, L, mid);
}
if(yr>mid){
update2(o*2+1, mid+1, R);
maintain(o*2, mid+1, R);
}
}
maintain(o, L, R);
}
ll query(int o,int L,int R)
{
ll ans=0;
if(yl<=L && yr>=R){
if(status[o] == 1)return fsum[o];
else return nsum[o];
} else {
int mid = L + ((R-L) >> 1);
if(yl <= mid)ans += query(o*2, L, mid);
if(yr > mid)ans += query(o*2+1, mid+1, R);
}
return ans;
}
int main()
{
// freopen("data.txt","r",stdin);
int n,m;
while(scanf("%d%d",&n,&m) != EOF){
build(1, 1, n);
for(int i=0; i<m; ++i){
int q;
int l,r;
scanf("%d%d%d",&q,&l,&r);
if (q == 1) {
id = l;
add = r;
update1(1, 1, n);
} else if (q == 3){
yl = l;yr = r;
update2(1, 1, n);
} else {
yl = l,yr = r;
ll ans = query(1, 1, n);
printf("%I64d\n",ans);
}
}
}
return 0;
}