Codeforces Round #373 (Div. 1) C.Sasha and Array

题目大意:给你一个长度为n的数列an,有两种操作

1、将L到R的ai加上X

2、询问L到R之间,f(aL)+f(aL+1)+……+f(aR)的和


考虑维护fib数列的转移

区间加,就相当于区间乘上一个矩阵

那么我们直接维护矩阵的合并和懒标记下推就可以了

乘的矩阵要预处理一下不然会多一个log的复杂度

#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2;
const long long MOD=1000000007;
struct Matrix 
{
	long long grid[N][N];
	int row,col;
	Matrix():row(N),col(N)
	{
    	memset(grid, 0, sizeof grid);
  	}
  	Matrix(int row, int col):row(row),col(col)
	{
    	memset(grid, 0, sizeof grid);
  	}
  	Matrix operator *(const Matrix &b)
	{
    	Matrix res(row, b.col);
    	for(int i = 0; i<res.row; i++)
      		for(int j = 0; j<res.col; j++)
        		for(int k = 0;k<col; k++)
        			res[i][j] = (res[i][j] + grid[i][k] * b.grid[k][j]) % MOD;
  		return res;
 	}
 	Matrix operator ^(long long exp)
	{
    	Matrix res(row, col);
    	for(int i = 0; i < row; i++)
			res[i][i] = 1;
    	Matrix temp = *this;
    	for(; exp > 0; exp >>= 1, temp = temp * temp)
      		if(exp & 1) res = temp * res;
    	return res;
  	}
  	long long* operator[](int index)
	{
    	return grid[index];
  	}
 	void print()
	{
    	for(int i = 0; i <row; i++)
		{
      		for(int j = 0; j < col-1; j++)
        		printf("%d ",grid[i][j]);
      		printf("%d\n",grid[i][col-1]);
    	}
	}
};
struct tree
{
	int l,r;
	long long x[2];
	long long s[3][3];
}tr[800001];
inline long long cale(int d)
{
	Matrix c(2,2);
	if(d<=2&&d>0)
		return 1;
	if(d==0)
		return 0;
	c[0][0]=0;
	c[0][1]=1;
	c[1][0]=1;
	c[1][1]=1;
	if(d>2)
		c=c^(d-2);
	return (c[0][1]+c[1][1])%MOD;
}
int a[100001];
inline void up(int p)
{
	tr[p].x[0]=(tr[p*2].x[0]+tr[p*2+1].x[0])%MOD;
	tr[p].x[1]=(tr[p*2].x[1]+tr[p*2+1].x[1])%MOD;
}
inline void push(int p)
{
	long long x0=tr[p*2].x[0],x1=tr[p*2].x[1];
	tr[p*2].x[0]=(x0*tr[p].s[1][1]+x1*tr[p].s[2][1])%MOD;
	tr[p*2].x[1]=(x0*tr[p].s[1][2]+x1*tr[p].s[2][2])%MOD;
	x0=tr[p*2+1].x[0],x1=tr[p*2+1].x[1];
	tr[p*2+1].x[0]=(x0*tr[p].s[1][1]+x1*tr[p].s[2][1])%MOD;
	tr[p*2+1].x[1]=(x0*tr[p].s[1][2]+x1*tr[p].s[2][2])%MOD;
	
	long long s11=tr[p*2].s[1][1],s12=tr[p*2].s[1][2],s21=tr[p*2].s[2][1],s22=tr[p*2].s[2][2];
	tr[p*2].s[1][1]=(s11*tr[p].s[1][1]+s12*tr[p].s[2][1])%MOD;
	tr[p*2].s[1][2]=(s11*tr[p].s[1][2]+s12*tr[p].s[2][2])%MOD;
	tr[p*2].s[2][1]=(s21*tr[p].s[1][1]+s22*tr[p].s[2][1])%MOD;
	tr[p*2].s[2][2]=(s21*tr[p].s[1][2]+s22*tr[p].s[2][2])%MOD;
	
	s11=tr[p*2+1].s[1][1],s12=tr[p*2+1].s[1][2],s21=tr[p*2+1].s[2][1],s22=tr[p*2+1].s[2][2];
	tr[p*2+1].s[1][1]=(s11*tr[p].s[1][1]+s12*tr[p].s[2][1])%MOD;
	tr[p*2+1].s[1][2]=(s11*tr[p].s[1][2]+s12*tr[p].s[2][2])%MOD;
	tr[p*2+1].s[2][1]=(s21*tr[p].s[1][1]+s22*tr[p].s[2][1])%MOD;
	tr[p*2+1].s[2][2]=(s21*tr[p].s[1][2]+s22*tr[p].s[2][2])%MOD;
	
	tr[p].s[1][1]=1;
	tr[p].s[1][2]=0;
	tr[p].s[2][1]=0;
	tr[p].s[2][2]=1;
}
inline void build(int p,int l,int r)
{
	tr[p].l=l;
	tr[p].r=r;
	if(l!=r)
	{
		int mid=(l+r)/2;
		build(p*2,l,mid);
		build(p*2+1,mid+1,r);
		up(p);
		tr[p].s[1][1]=1;
		tr[p].s[1][2]=0;
		tr[p].s[2][1]=0;
		tr[p].s[2][2]=1;
	}
	else
	{
		tr[p].x[0]=cale(a[l]-1);
		tr[p].x[1]=cale(a[l]);
		tr[p].s[1][1]=1;
		tr[p].s[1][2]=0;
		tr[p].s[2][1]=0;
		tr[p].s[2][2]=1;
	} 
}
inline long long query(int p,int l,int r)
{
	if(l<=tr[p].l&&tr[p].r<=r)
		return tr[p].x[1];
	else
	{
		push(p);
		int mid=(tr[p].l+tr[p].r)/2;
		long long ans=0;
		if(l<=mid)
			ans+=query(p*2,l,r);
		if(r>mid)
			ans+=query(p*2+1,l,r);
		ans=ans%MOD;
		return ans;
	}
}
Matrix c(2,2);
long long xt[3][3];
inline void change(int p,int l,int r,int x)
{
	if(l<=tr[p].l&&tr[p].r<=r)
	{
//		c.print();
		long long x0=tr[p].x[0],x1=tr[p].x[1];
		tr[p].x[0]=(x0*c[0][0]+x1*c[1][0])%MOD;
		tr[p].x[1]=(x0*c[0][1]+x1*c[1][1])%MOD;
		
		long long s11=tr[p].s[1][1],s12=tr[p].s[1][2],s21=tr[p].s[2][1],s22=tr[p].s[2][2];
		tr[p].s[1][1]=(s11*c[0][0]+s12*c[1][0])%MOD;
		tr[p].s[1][2]=(s11*c[0][1]+s12*c[1][1])%MOD;
		tr[p].s[2][1]=(s21*c[0][0]+s22*c[1][0])%MOD;
		tr[p].s[2][2]=(s21*c[0][1]+s22*c[1][1])%MOD;
	}
	else
	{
		push(p);
		int mid=(tr[p].l+tr[p].r)/2;
		if(l<=mid)
			change(p*2,l,r,x);
		if(r>mid)
			change(p*2+1,l,r,x);
		up(p);
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	int i;
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	build(1,1,n);
	int x,s,t;
	for(i=1;i<=m;i++)
	{
		scanf("%d",&x);
		if(x==2)
		{
			scanf("%d%d",&s,&t);
			printf("%I64d\n",query(1,s,t));
		}
		else
		{
			scanf("%d%d%d",&s,&t,&x);		
			c[0][0]=0;
			c[0][1]=1;
			c[1][0]=1;
			c[1][1]=1;
			c=c^x;
			change(1,s,t,x);
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值