CF316E3 Summer Homework

题意

参考这篇博客

看到区间问题首先考虑线段树,之后考虑如何合并区间:

比如我们现在求出了区间([l,mid])和区间([mid+1,r])的答案,现在我们要求出([l,r])的答案,我们需要使([mid+1,r])的答案中每个斐波那契系数的下标加上(mid-l+1),这个看似无法处理,我们不妨先考虑只让下标加(1)的情况。

对于区间([l,r])
(s_i=sumlimits_{j=0}^{r-l}f_{j+i}a_j),那么在区间([l,r])上记录的答案就是(s_0)
(s_{i-1}+s_{i-2})
(=sumlimits_{j=0}^{r-l}f_{j+i-1}a_j+sumlimits_{j=0}^{n}f_{j+i-2}a_j)
(=sumlimits_{j=0}^{r-l}(f_{j+i-1}+f_{j+i-2})a_j)
(=sumlimits_{j=0}^{r-l}f_{j+i}a_j)
(=s_i)
(s_i=s_{i-1}+s_{i-2})

于是我们现在能从(s_{i-1})(s_{i-2})转移到(s_i),但是我们显然不能在线段树上递推或者记录所有的(s_i),因此考虑如何用(s_0)(s_1)推出所有(s_i)

不妨设(s_0=A,s_1=B),那么有:
(s_2=s_0+s_1=1A+1B=f_0A+f_1B)
(s_3=s_1+s_2=1B+1A+1B=f_1A+f_2B)
(s_4=s_2+s_3=(f_0+f_1)A+(f_1+f_2)B=f_2A+f_3B)
(... ...)
(f_i=f_{i-2}A+f_{i-1}B)

(f_i=f_{i-2}s_0+f_{i-1}s_1)

那么我们对每个节点维护(s_0,s_1)即可,现在我们可以合并区间了。

区间加的话,我们肯定是打标记,假设对([l,r])区间加(k)

(s'_0=sumlimits_{j=0}^{r-l}f_j*(a_j+k))
(=sumlimits_{j=0}^{r-l}f_ja_j+sumlimits_{j=0}^{r-l}f_jk)

同理,(s'_1=sumlimits_{j=0}^{r-l}f_{j+1}a_j+sumlimits_{j=0}^{r-l}f_{j+1}k)

我们只要求一个斐波那契数列的前缀和,之后对区间的(s_0,s_1)加上上面的那个只跟(k)有关的东西就好了。

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define s0(p) (seg[p].s0)
#define s1(p) (seg[p].s1)
#define tag(p) (seg[p].tag)
const int maxn=2e5+10;
const int mod=1000000000;
int n,m;
ll a[maxn],fib[maxn],sum[maxn];
struct Seg{ll s0,s1,tag;}seg[maxn<<2];
inline void up(int p,int l,int r)
{
	int mid=(l+r)>>1;
	s0(p)=(s0(ls(p))+(s0(rs(p))*fib[mid-l-1]%mod+s1(rs(p))*fib[mid-l]%mod)%mod)%mod;
	s1(p)=(s1(ls(p))+(s0(rs(p))*fib[mid-l]%mod+s1(rs(p))*fib[mid-l+1]%mod)%mod)%mod;
}
inline void down(int p,int l,int r)
{
	if(!tag(p))return;
	int mid=(l+r)>>1,k=tag((p));
	tag(ls(p))=(tag(ls(p))+k)%mod;tag(rs(p))=(tag(rs(p))+k)%mod;
	s0(ls(p))=(s0(ls(p))+sum[mid-l]*k%mod)%mod;
	s1(ls(p))=(s1(ls(p))+(sum[mid-l+1]-sum[0]+mod)%mod*k%mod)%mod;
	s0(rs(p))=(s0(rs(p))+sum[r-mid-1]*k%mod)%mod;
	s1(rs(p))=(s1(rs(p))+(sum[r-mid]-sum[0]+mod)%mod*k%mod)%mod;
	tag(p)=0;
}
void build(int p,int l,int r)
{
	if(l==r){s0(p)=s1(p)=a[l]%mod;return;}
	int mid=(l+r)>>1;
	build(ls(p),l,mid);build(rs(p),mid+1,r);
	up(p,l,r);
}
void change(int p,int l,int r,int pos,ll k)
{
	if(l==r){s0(p)=s1(p)=k%mod;tag(p)=0;return;}
	down(p,l,r);
	int mid=(l+r)>>1;
	if(pos<=mid)change(ls(p),l,mid,pos,k);
	else change(rs(p),mid+1,r,pos,k);
	up(p,l,r);
}
void add(int p,int l,int r,int ql,int qr,ll k)
{
	if(l>=ql&&r<=qr)
	{
		tag(p)=(tag(p)+k)%mod;
		s0(p)=(s0(p)+sum[r-l]*k%mod)%mod;
		s1(p)=(s1(p)+(sum[r-l+1]-sum[0]+mod)%mod*k%mod)%mod;
		return;
	}
	down(p,l,r);
	int mid=(l+r)>>1;
	if(ql<=mid)add(ls(p),l,mid,ql,qr,k);
	if(qr>mid)add(rs(p),mid+1,r,ql,qr,k);
	up(p,l,r);
}
ll query(int p,int l,int r,int ql,int qr)
{
	if(l>=ql&&r<=qr)
	{
		if(l==ql)return s0(p);
		else if(l==ql+1)return s1(p);
		else return (s0(p)*fib[l-ql-2]%mod+s1(p)*fib[l-ql-1]%mod)%mod;
	}
	down(p,l,r);
	int mid=(l+r)>>1;ll res=0;
	if(ql<=mid)res=(res+query(ls(p),l,mid,ql,qr))%mod;
	if(qr>mid)res=(res+query(rs(p),mid+1,r,ql,qr))%mod;
	return res;
}
int main()
{
	scanf("%d%d",&n,&m);
	fib[0]=fib[1]=1;
	for(int i=2;i<=n;i++)fib[i]=(fib[i-2]+fib[i-1])%mod;
	sum[0]=1;
	for(int i=1;i<=n;i++)sum[i]=(sum[i-1]+fib[i])%mod;
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	build(1,1,n);
	for(int i=1;i<=m;i++)
	{
		int op,l,r;ll k;scanf("%d%d%d",&op,&l,&r);
		if(op==1)change(1,1,n,l,r);
		if(op==2)printf("%lld
",query(1,1,n,l,r));
		if(op==3)scanf("%lld",&k),add(1,1,n,l,r,k);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/nofind/p/12159549.html