E3. Summer Homework(线段树+矩阵)
题目链接
题意是给一个序列,支持三种操作
1、把第x个数改为v
2、求l到r之间的和
3、给l到r之间加上一个数字
和函数定义是Sum(l,r) = a[l]*f[0] + a[l+1]*f[1] + a[l+2]*f[2] + ……+a[r]*f[r-l]
f[]为斐波那契数列
这个题其实即使没有第一种第三种操作,也是很难做的 ,我们考虑用一个 线段树来维护,
比如[1,8]这个区间,线段树中[1,4]这个节点我们存一个(a1*f0+……+a4*f3),[5,8]这个节点我们可以存(a5*f0+……+a8*f3),但是怎么把这两段合并到[1,8]这个节点上去呢
1*a5 + 1*a6 + 2*a7 + 3*a8=>1*a5 + 2 * a6 + 3 * a7 + 5 *a8
右边减去左边得到 0*a5 + 1 * a6 + 1 * a7 + 2 *a8
以此类推,可以得到合并后的结果
于是我们线段树节点中存两个东西[A,B],利用斐波那契的矩阵,右子树乘上x次之后(x为左子树区间的长度),合并可得到当前节点的值
在查询的时候也同理进行合并,然后第一种和第三种操作,我们可以很容易算出其每次加的数字对整段的贡献,直接加上去就行
#include<cmath>
#include<algorithm>
#include<cstring>
#include<string>
#include<set>
#include<map>
#include<time.h>
#include<cstdio>
#include<vector>
#include<list>
#include<stack>
#include<queue>
#include<iostream>
#include<stdlib.h>
using namespace std;
#define LONG long long
const LONG INF=0x3f3f3f3f;
const LONG MOD=1e9 ;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define lson l , mid , rt<< 1
#define rson mid + 1 ,r , (rt<<1)|1
//#define root 1, n , 1
struct Matr{
LONG matr[2][2] ;
void Init()
{
clr0(matr) ;
}
} F[210000] ;
Matr Multi(Matr a , Matr b)
{
Matr res ; res.Init() ;
for(int i = 0 ; i < 2 ; ++ i)
for(int j = 0 ; j < 2 ; ++ j)
for(int k = 0 ; k < 2 ; ++ k)
res.matr[i][j] = (res.matr[i][j] + a.matr[i][k] * b.matr[k][j]) % MOD ;
return res ;
}
Matr X;
LONG Fib[201000] ;
LONG a[200100] ;
struct Tree{
LONG A , B ;
}tree[200010*4] ;
LONG lazy[200010 * 4] ;
void Push_up(int l,int r ,int rt )
{
int mid = (l+r) / 2;
Matr tmp = F[mid-l +1];
tree[rt].A = tree[rt<<1].A + (tree[rt<<1|1].A *tmp.matr[0][0] % MOD ) + (tree[rt<<1|1].B * tmp.matr[1][0] % MOD ) ;tree[rt].A %= MOD ;
tree[rt].B = tree[rt<<1].B + ( tree[rt<<1|1].A*tmp.matr[0][1] % MOD) + ( tree[rt<<1|1].B*tmp.matr[1][1]%MOD ) ;tree[rt].B %= MOD ;
}
void Build(int l ,int r ,int rt )
{
lazy [rt] = 0 ;
if(l == r)
{
tree[rt].A = a[l] ;
tree[rt].B = 0 ;
return ;
}
int mid = (l+r)/2 ;
Build(lson ) ;
Build( rson ) ;
Push_up( l , r , rt ) ;
}
void Push_down(int l, int r ,int rt )
{
int mid = (l +r) /2 ;
if(lazy[rt])
{
LONG ret1 = (F[mid - l +1 +2-1].matr[0][0] - 1) * lazy[rt] % MOD ;
LONG ret2 = (F[mid-l + 2-1].matr[0][0] - 1) * lazy[rt] % MOD ;
tree[rt<<1].A = (tree[rt<<1].A + ret1) % MOD ;
tree[rt<<1].B = (tree[rt<<1].B + ret2) % MOD ;
ret1 = (F[r-mid + 2-1].matr[0][0] - 1) * lazy[rt]% MOD ;
ret2 = (F[r - mid - 1 + 2 -1].matr[0][0] - 1) * lazy[rt] % MOD ;
tree[rt<<1|1].A = (tree[rt<<1|1].A + ret1 ) % MOD ;
tree[rt<<1|1].B = (tree[rt<<1|1].B + ret2) % MOD ;
lazy[rt<<1] += lazy[rt] ;lazy[rt<<1] %= MOD ;
lazy[rt<<1|1] += lazy[rt] ; lazy[rt<<1|1] %= MOD ;
lazy[rt] = 0 ;
}
}
void Update1(int L ,int R , int l , int r ,int rt , LONG val)
{
if(L <= l && r <= R )
{
LONG ret1 = (F[r-l+1 + 2-1].matr[0][0] - 1)*val % MOD ;
LONG ret2 = (F[r-l + 2-1].matr[0][0] - 1) * val % MOD ;
tree[rt].A = (tree[rt].A +ret1 )%MOD ;
tree[rt].B =(tree[rt].B + ret2 ) % MOD ;
lazy[rt] += val ;
return ;
}
Push_down(l , r , rt ) ;
int mid = (l + r ) / 2;
if(L <= mid)
Update1(L , R , lson , val ) ;
if(R > mid )
Update1(L ,R , rson , val) ;
Push_up(l , r, rt) ;
}
Tree Que(int L ,int R ,int l ,int r , int rt )
{
if(L <= l && r <=R)
return tree[rt] ;
int mid = (l + r) / 2;
Push_down(l , r , rt ) ;
Tree res1 , res2,ans ;
if(L <= mid && R <= mid )
return Que(L , R , lson ) ;
else if(L > mid && R > mid )
return Que(L ,R ,rson ) ;
else
{
Matr tmp = F[mid-max(L,l)+1] ;
res1 = Que(L,R,lson ) ;
res2 = Que(L ,R ,rson ) ;
ans.A = ( res1.A + (res2.A *tmp.matr[0][0] % MOD ) + (res2.B * tmp.matr[1][0] % MOD ) )%MOD ;
ans.B = ( res1.B + (res2.A*tmp.matr[0][1] % MOD) + ( res2.B*tmp.matr[1][1]%MOD ) ) % MOD ;
return ans ;
}
}
int main()
{
int n , m ;
X.matr[0][0] = 1 ; X.matr[1][0] = 1 ;X.matr[0][1] = 1 ;X.matr[1][1] = 0 ;
F[1] = X ;
for(int i = 2 ; i <= 200000 ; ++i)
F[i] = Multi(F[i-1] , X) ;
while(cin >> n >> m)
{
for(int i = 1 ;i <= n ; ++ i)
scanf( "%lld",&a[i] ) ;
Build(1,n,1) ;
int t ;
int l , r ;
LONG val ;
LONG temp ;
Tree RES ;
while(m -- )
{
scanf("%d",&t) ;
if(t == 1)
{
scanf("%d%lld",&l,&val) ;
RES = Que(l,l,1,n,1) ;
temp = val - RES.A ;
Update1(l , l ,1,n,1,temp ) ;
}
else if(t ==2 )
{
scanf("%d%d",&l,&r) ;
RES = Que(l ,r , 1,n,1) ;
printf("%lld\n",RES.A) ;
}
else
{
scanf("%d%d%lld",&l,&r,&val) ;
Update1(l ,r ,1,n,1,val) ;
}
}
}
}