Codeforces 316 E3 线段树

题目链接


题意

给定一个长度为\(n\)序列\(a\),需要支持如下操作

  • 单点修改

  • 对于区间\([l..r]\),求\(\sum_{i=0}^{r-l}f_i*a_{l+i}\),模\(10^9\),其中\(f\)是斐波那契数列,\(f_0=f_1=1\)

  • 区间加

做法

建线段树,对于一个节点\([l..r]\),记

\[s_k=\sum_{i=0}^{r-l}f_{i+k}*a_{l+i} \]

存在以下性质

\[\begin{align} &s_{k-2}+s_{k-1}\\ =&\sum_{i=0}^{r-l}(f_{i+k-2}+f_{i+k-1})*a_{l+i}\\ =&\sum_{i=0}^{r-l}f_{i+k}*a_{l+i}\\ =&s_k \end{align} \]

只需要维护\(s_0\)\(s_1\),预处理斐波那契数列作为系数,可以\(O(1)\)求出\(s_k\)

合并两个区间的时候,需要求出第二个区间的\(s_{len},s_{len+1}\),其中\(len\)是第一个区间的长度

区间加,可以利用$$\sum_{i=0}^nf_i=f_{n+2}-1$$快速修改

#include<cstdio>
#include<algorithm>
#include<ctype.h>
#include<string.h>
#include<math.h>

using namespace std;
#define ll long long

inline char read() {
	static const int IN_LEN = 1000000;
	static char buf[IN_LEN], *s, *t;
	return (s == t ? t = (s = buf) + fread(buf, 1, IN_LEN, stdin), (s == t ? -1 : *s++) : *s++);
}
template<class T>
inline void read(T &x) {
	static bool iosig;
	static char c;
	for (iosig = false, c = read(); !isdigit(c); c = read()) {
		if (c == '-') iosig = true;
		if (c == -1) return;
	}
	for (x = 0; isdigit(c); c = read()) x = ((x + (x << 2)) << 1) + (c ^ '0');
	if (iosig) x = -x;
}
const int OUT_LEN = 10000000;
char obuf[OUT_LEN], *ooh = obuf;
inline void print(char c) {
	if (ooh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), ooh = obuf;
	*ooh++ = c;
}
template<class T>
inline void print(T x) {
	static int buf[30], cnt;
	if (x == 0) print('0');
	else {
		if (x < 0) print('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) print((char)buf[cnt--]);
	}
}
inline void flush() { fwrite(obuf, 1, ooh - obuf, stdout); }
const int N = 200005, P = 1000000000;
int n, m, f[N], a[N], lazy[N<<2];
struct st{
	int a, b, len;
	inline st(){}
	inline st(int a_, int b_, int len_){ a=a_, b=b_, len=len_;}
	inline st operator *(const st &rhs)const{
		return st((a+(ll)rhs.a*f[len-1]+(ll)rhs.b*f[len])%P, (b+(ll)rhs.a*f[len]+(ll)rhs.b*f[len+1])%P, len+rhs.len);
	}
}s[N<<2];
void build(int l, int r, int t){
	if(l==r) return (void)(s[t].a=s[t].b=a[l], s[t].len=1);
	int mid=l+r>>1, k=t<<1;
	build(l, mid, k), build(mid+1, r, k|1);
	s[t]=s[k]*s[k|1];
}
inline void add(int t, int x){
	(lazy[t]+=x)%=P;
	s[t].a=(s[t].a+(ll)(f[s[t].len+2]-1)*x)%P;
	s[t].b=(s[t].b+(ll)(f[s[t].len+3]-2)*x)%P;
}
void modify(int l, int r, int t, int x, int y){
	if(l==r) return (void)(s[t].a=s[t].b=y);
	int mid=l+r>>1, k=t<<1;
	if(lazy[t]) add(k, lazy[t]), add(k|1, lazy[t]), lazy[t]=0;
	if(x<=mid) modify(l, mid, k, x, y); else modify(mid+1, r, k|1, x, y);
	s[t]=s[k]*s[k|1];
}
st query(int l, int r, int t, int L, int R){
	if(L<=l && r<=R) return s[t];
	int mid=l+r>>1, k=t<<1;
	if(lazy[t]) add(k, lazy[t]), add(k|1, lazy[t]), lazy[t]=0;
	if(R<=mid) return query(l, mid, k, L, R);
	if(L>mid) return query(mid+1, r, k|1, L, R);
	return query(l, mid, k, L, R)*query(mid+1, r, k|1, L, R);
}
void change(int l, int r, int t, int L, int R, int x){
	if(L<=l && r<=R) return add(t, x);
	int mid=l+r>>1, k=t<<1;
	if(lazy[t]) add(k, lazy[t]), add(k|1, lazy[t]), lazy[t]=0;
	if(L<=mid) change(l, mid, k, L, R, x);
	if(R>mid) change(mid+1, r, k|1, L, R, x);
	s[t]=s[k]*s[k|1];
}
int main() {
	read(n), read(m);
	f[1]=f[2]=1;
	for(int i=3; i<=n+3; ++i) f[i]=(f[i-1]+f[i-2])%P;
	for(int i=1; i<=n; ++i) read(a[i]);
	build(1, n, 1);
	while(m--){
		static int opt, l, r, x;
		read(opt), read(l), read(r);
		if(opt==1) modify(1, n, 1, l, r);
		else if(opt==2) print(query(1, n, 1, l, r).a), print('\n');
		else read(x), change(1, n, 1, l, r, x);
	}
	return flush(), 0;
}
posted @ 2018-09-15 15:21  CMXRYNP  阅读(214)  评论(0编辑  收藏  举报