CF316E3 Summer Homework

题意

参考这篇博客

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

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

对于区间\([l,r]\)
\(s_i=\sum\limits_{j=0}^{r-l}f_{j+i}a_j\),那么在区间\([l,r]\)上记录的答案就是\(s_0\)
\(s_{i-1}+s_{i-2}\)
\(=\sum\limits_{j=0}^{r-l}f_{j+i-1}a_j+\sum\limits_{j=0}^{n}f_{j+i-2}a_j\)
\(=\sum\limits_{j=0}^{r-l}(f_{j+i-1}+f_{j+i-2})a_j\)
\(=\sum\limits_{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=\sum\limits_{j=0}^{r-l}f_j*(a_j+k)\)
\(=\sum\limits_{j=0}^{r-l}f_ja_j+\sum\limits_{j=0}^{r-l}f_jk\)

同理,\(s'_1=\sum\limits_{j=0}^{r-l}f_{j+1}a_j+\sum\limits_{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\n",query(1,1,n,l,r));
		if(op==3)scanf("%lld",&k),add(1,1,n,l,r,k);
	}
	return 0;
}
posted @ 2020-01-07 08:53  nofind  阅读(209)  评论(0编辑  收藏  举报