题目链接
【CodeForces 316E3】Summer Homework
题目大意
给定一个数列
a1
a
1
,
a2
a
2
···
an
a
n
,支持三种操作:
1 x v
表示
ax←v
a
x
←
v
2 l r
表示询问
∑r−li=0fiai+l
∑
i
=
0
r
−
l
f
i
a
i
+
l
(f0=1,f1=1,fi=fi−2+fi−1)
(
f
0
=
1
,
f
1
=
1
,
f
i
=
f
i
−
2
+
f
i
−
1
)
3 l r v
表示对于所有的
l≤x≤r
l
≤
x
≤
r
,
ax←ax+v
a
x
←
a
x
+
v
题解
果断使用线段树
记
si=∑ij=0fi
s
i
=
∑
j
=
0
i
f
i
记
point
p
o
i
n
t
为当前节点
记
lftson
l
f
t
s
o
n
为当前节点的左儿子
记
rhtson
r
h
t
s
o
n
为当前节点的右儿子
每一个节点维护
len=区间长度
l
e
n
=
区
间
长
度
,
sum0=∑r−li=0fiai+l
s
u
m
0
=
∑
i
=
0
r
−
l
f
i
a
i
+
l
和
sum1=∑r−li=0fi+1ai+l
s
u
m
1
=
∑
i
=
0
r
−
l
f
i
+
1
a
i
+
l
方法一:使用矩阵快速幂
问题一:如何合并两个节点?
(sum0[point],sum1[point])=(sum0[lftson],sum1[lftson])+(sum0[rhtson],sum1[rhtson])×(0111)len[lftson]
(
s
u
m
0
[
p
o
i
n
t
]
,
s
u
m
1
[
p
o
i
n
t
]
)
=
(
s
u
m
0
[
l
f
t
s
o
n
]
,
s
u
m
1
[
l
f
t
s
o
n
]
)
+
(
s
u
m
0
[
r
h
t
s
o
n
]
,
s
u
m
1
[
r
h
t
s
o
n
]
)
×
(
0
1
1
1
)
l
e
n
[
l
f
t
s
o
n
]
问题二:区间加法对节点的贡献是什么?
∑len[point]I=0fi=v×len[point]
∑
I
=
0
l
e
n
[
p
o
i
n
t
]
f
i
=
v
×
l
e
n
[
p
o
i
n
t
]
方法二:不使用矩阵
问题:如何合并两个节点?
sum0[point]=sum0[lftson]+sum0[rhtson]×flen[lftson]−2+sum1[rhtson]×flen[lftson]−1
s
u
m
0
[
p
o
i
n
t
]
=
s
u
m
0
[
l
f
t
s
o
n
]
+
s
u
m
0
[
r
h
t
s
o
n
]
×
f
l
e
n
[
l
f
t
s
o
n
]
−
2
+
s
u
m
1
[
r
h
t
s
o
n
]
×
f
l
e
n
[
l
f
t
s
o
n
]
−
1
sum1[point]=sum1[lftson]+sum0[rhtson]×flen[lftson]−1+sum1[rhtson]×flen[lftson]
s
u
m
1
[
p
o
i
n
t
]
=
s
u
m
1
[
l
f
t
s
o
n
]
+
s
u
m
0
[
r
h
t
s
o
n
]
×
f
l
e
n
[
l
f
t
s
o
n
]
−
1
+
s
u
m
1
[
r
h
t
s
o
n
]
×
f
l
e
n
[
l
f
t
s
o
n
]
总结:方法二只是形式上省掉了矩阵乘法,本质没有改变,但是代码变得更加简洁,常数更小,跑得更快。
再转一个很不错的题解:Ice Princess 的博客
代码(方法二)
#include <cstdio>
#define mxn 200000
#define mod 1000000000
#define ls (p<<1)
#define rs (ls|1)
#define md (l+r>>1)
int n,m,f[mxn|1],s[mxn|1],a[mxn<<2|2];
inline int fibonacci(int p);
inline int plusmod(int x,int y);
inline int plusmod(int x,int y,int z);
inline int mulmod(int x,int y);
inline int minusmid(int x,int y);
struct node {
int len,sum0,sum1;
node() {}
node(int l,int s0,int s1) {
len=l,sum0=s0,sum1=s1;
}
node operator+(const node &o) const {
node x(len+o.len,0,0);
x.sum0=plusmod(sum0,mulmod(o.sum0,fibonacci(len-2)),mulmod(o.sum1,fibonacci(len-1)));
x.sum1=plusmod(sum1,mulmod(o.sum0,fibonacci(len-1)),mulmod(o.sum1,fibonacci(len)));
return x;
}
} t[mxn<<2|2];
inline int plusmod(int x,int y) {
x+=y,x-=(x>=mod?mod:0);
return x;
}
inline int plusmod(int x,int y,int z) {
return plusmod(plusmod(x,y),z);
}
inline int minusmod(int x,int y) {
x-=y,x+=(x<0?mod:0);
return x;
}
inline int mulmod(int x,int y) {
return 1ll*x*y%mod;
}
void prework() {
f[0]=f[1]=1;
for(int i=2;i<=mxn;i++)
f[i]=plusmod(f[i-1],f[i-2]);
s[0]=1;
for(int i=1;i<=mxn;i++)
s[i]=plusmod(s[i-1],f[i]);
}
inline int fibonacci(int p) {
return p<0?0:f[p];
}
void build(int p,int l,int r) {
if(l==r) {
scanf("%d",&t[p].sum0);
t[p].len=1,t[p].sum1=t[p].sum0;
return;
}
build(ls,l,md);
build(rs,md+1,r);
t[p]=t[ls]+t[rs];
}
void update(int p,int l,int r,int x) {
int len=r-l+1;
t[p].sum0=plusmod(t[p].sum0,mulmod(x,s[len-1]));
t[p].sum1=plusmod(t[p].sum1,minusmod(mulmod(x,s[len]),x));
}
void push_down(int p,int l,int r) {
if(!a[p]) return;
if(l-r) {
a[ls]=plusmod(a[ls],a[p]);
a[rs]=plusmod(a[rs],a[p]);
update(ls,l,md,a[p]);
update(rs,md+1,r,a[p]);
}
a[p]=0;
}
void change(int p,int l,int r,int x,int y) {
if(l==r) {
t[p]=node(1,y,y);
return;
}
push_down(p,l,r);
if(x<=md) change(ls,l,md,x,y);
else change(rs,md+1,r,x,y);
t[p]=t[ls]+t[rs];
}
void modify(int p,int l,int r,int lx,int rx,int x) {
if(l==lx&&r==rx) {
a[p]=plusmod(a[p],x);
update(p,l,r,x);
return;
}
push_down(p,l,r);
if(rx<=md) modify(ls,l,md,lx,rx,x);
else if(lx>md) modify(rs,md+1,r,lx,rx,x);
else modify(ls,l,md,lx,md,x),modify(rs,md+1,r,md+1,rx,x);
t[p]=t[ls]+t[rs];
}
node query(int p,int l,int r,int lx,int rx) {
if(l==lx&&r==rx) return t[p];
push_down(p,l,r);
if(rx<=md) return query(ls,l,md,lx,rx);
if(lx>md) return query(rs,md+1,r,lx,rx);
return query(ls,l,md,lx,md)+query(rs,md+1,r,md+1,rx);
}
int main() {
prework();
scanf("%d%d",&n,&m);
build(1,1,n);
int op,x,y,z;
for(int i=1;i<=m;i++) {
scanf("%d%d%d",&op,&x,&y);
switch(op) {
case 1:
change(1,1,n,x,y);
break;
case 2:
printf("%d\n",query(1,1,n,x,y).sum0);
break;
case 3:
scanf("%d",&z);
modify(1,1,n,x,y,z);
}
}
return 0;
}