【CF316E3】Summer Homework - 線段樹

題目描述

By the age of three Smart Beaver mastered all arithmetic operations and got this summer homework from the amazed teacher:
You are given a sequence of integers \(a_{1},a_{2},...,a_{n}\). Your task is to perform on it mm consecutive operations of the following type:

  1. For given numbers \(x_{i}\) and \(v_{i}\) assign value \(v_{i}\) to element \(a_{x_i}\).
  2. For given numbers \(l_{i}\) and \(r_{i}\) you've got to calculate sum \(\Sigma_{x=0}^{r_i-l_i}f_xa_{l_i+x}\), where \(f_{0}=f_{1}=1\) and at \(i\geq 2\) : \(f_{i}=f_{i-1}+f_{i-2}\).
  3. For a group of three numbers \(l_{i}\) \(r_{i}\) \(d_{i}\) you should increase value \(a_{x}\) by \(d_{i}\) for all \(x\) \((l_{i}<=x<=r_{i})\)).
    Smart Beaver planned a tour around great Canadian lakes, so he asked you to help him solve the given problem.

題目大意

  • 在這裏,我們用 \(f_i\) 表示第 \(i\) 個斐波那契數 \(f_0=1,f_1=1,f_i=f_{i-1}+f_{i-2}(i\ge 2)\)
  • 給定 \(n\) 個數的序列 \(a\)\(m\) 次操作。操作有三種:
    1. 1 x v:將 \(a_x\) 賦值爲 \(v\)
    2. 2 l r:求 \(\sum_{x=0}^{r-l}(f_x\cdot a_{l+x})\ mod\ 10^9\)
    3. 3 l r d:將 \(a_l\sim a_r\) 加上 \(d\)
  • \(1\le n,m\le 2\times10^5\)\(0\le a_i,v,d\le 10^5\)

思路

對於一個區間 \([l,r]\),用線段樹維護一個 \(s_n\),其中 \(s_n=\Sigma_{i=0}^{r-l}a_{l+i}f_{i+n}\),即 \({f}\) 從第 \(n\) 項開始與 \({a}\) 對應相乘求和
那麼題中所求就是 \(s_0\),對於一個區間 seg,它的左右兒子是 lsonrson,那麼有 \(seg.s_n = lson.s_n+rson.s_{n+lson.len}\)
同時,\({s}\)\({f}\) 有相同的遞推性質,即 \(s_n=s_{n-1}+s_{n-2}\),因爲:
\(s_{n-1}+s_{n-2}=\Sigma_{i=0}^{r-l}a_{l+i}f_{i+n-1}+\Sigma_{i=0}^{r-l}a_{l+i}f_{i+n-2}=\Sigma_{i=0}^{r-l}a_{l+i}(f_{i+n-1}+f_{i+n-2})=\Sigma_{i=0}^{r-l}a_{l+i}f_{i+n}=s_n\)
那麼只用線段樹記錄下 \(s_0,s_1\) ,就可遞推出 \(s_n\)

\[s_2=s_0+s_1 \]

\[s_3=s_1+s_2=s_0+2s_1 \]

\[s_4=s_2+s_3=2s_0+3s_1 \]

\[s_5=s_3+s_4=3s_0+5s_1 \]

\[\vdots \]

\[s_n=f_{n-2}s_0+f_{n-1}s_1 \]

#include <algorithm>
#include <cstdio>
using namespace std;
const int maxn = 2e5 + 10;
const int mod = 1e9;
int n,m,f[maxn] = { 1,1 },pre[maxn] = { 1,2 },laz[maxn<<2];
struct func {
	int s0,s1;
	inline int s(int x) {
		if (x == 0) return s0;
		if (x == 1) return s1;
		return (1ll*f[x-2]*s0%mod+1ll*f[x-1]*s1%mod)%mod;
	}
} t[maxn<<2];
inline void pushup(int root,int l,int r) {
	int mid = l+r>>1;
	t[root].s0 = (t[root<<1].s0+t[root<<1|1].s(mid-l+1))%mod;
	t[root].s1 = (t[root<<1].s1+t[root<<1|1].s(mid-l+2))%mod;
}
inline void pushdown(int root,int l,int r) {
	int mid = l+r>>1;
	if (laz[root]) {
		(laz[root<<1] += laz[root])%= mod;
		(laz[root<<1|1] += laz[root])%= mod;
		(t[root<<1].s0 += 1ll*laz[root]*pre[mid-l]%mod) %= mod;
		(t[root<<1|1].s0 += 1ll*laz[root]*pre[r-mid-1]%mod) %= mod;
		(t[root<<1].s1 += 1ll*laz[root]*(pre[mid-l+1]-pre[0])%mod) %= mod;
		(t[root<<1|1].s1 += 1ll*laz[root]*(pre[r-mid]-pre[0])%mod) %= mod;
		laz[root] = 0;
	}
}
inline void build(int l,int r,int root) {
	if (l == r) {
		scanf("%d",&t[root].s0);
		t[root].s1 = t[root].s0;
		return;
	}
	int mid = l+r>>1;
	build(l,mid,root<<1);
	build(mid+1,r,root<<1|1);
	pushup(root,l,r);
}
inline void update(int l,int r,int ul,int ur,int root,int x) {
	if (l > ur || r < ul) return;
	if (ul <= l && r <= ur) {
		laz[root] += x;
		(t[root].s0 += 1ll*x*pre[r-l]%mod) %= mod;
		(t[root].s1 += 1ll*x*(pre[r-l+1]-pre[0])%mod) %= mod;
		return;
	}
	pushdown(root,l,r);
	int mid = l+r>>1;
	update(l,mid,ul,ur,root<<1,x);
	update(mid+1,r,ul,ur,root<<1|1,x);
	pushup(root,l,r);
}
inline func query(int l,int r,int ql,int qr,int root) {
	if (ql <= l && r <= qr) return t[root];
	pushdown(root,l,r);
	int mid = l+r>>1;
	if (mid < ql) return query(mid+1,r,ql,qr,root<<1|1);
	else if (mid >= qr) return query(l,mid,ql,qr,root<<1);
	else {
		func ls = query(l,mid,ql,qr,root<<1),rs = query(mid+1,r,ql,qr,root<<1|1);
		return (func){ (ls.s0+rs.s(mid-max(l,ql)+1))%mod,(ls.s1+rs.s(mid-max(l,ql)+2))%mod };
	}
}
int main() {
	scanf("%d%d",&n,&m);
	for (int i = 2;i <= n;i++) {
		f[i] = (f[i-1]+f[i-2])%mod;
		pre[i] = (pre[i-1]+f[i])%mod;
	}
	for (build(1,n,1);m--;) {
		int op,l,r,d;
		scanf("%d%d%d",&op,&l,&r);
		if (op == 1) update(1,n,l,l,1,r-query(1,n,l,l,1).s0);
		if (op == 2) printf("%d\n",query(1,n,l,r,1).s0);
		if (op == 3) {
			scanf("%d",&d);
			update(1,n,l,r,1,d);
		}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章