您的位置:首页 > 其它

【Codeforces 718C&719E】Sasha and Array【线段树成段更新+矩阵快速幂】

2016-10-04 16:57 453 查看
题意:
给你一个数列,有两种操作1 l r x 给[l,r]区间上的数加上x, 2 l r 询问[l,r]区间fibonacci数列的和(f[l]+f[l+1]+……f[r])

题解:
这样的区间加和区间询问很容易想到线段树成段更新,关键是怎么存储信息,我们都知道fibonacci数列可以用矩阵快速幂递推,基础矩阵是a[0][0]=1,a[0][1]=1,a[1][0]=1,a[1][1]=0,a[0][0]中存储的就是当前的fibonacci值(不会这个可以先做下poj3070)

然后我们可以在线段树的每个节点都存一个2*2的矩阵,这个矩阵就是当前fibonacci数列的运算矩阵,这是线段树的建树过程,

现在我们来看操作1 [l,r]区间上的数加上x 我们设A[x]矩阵代表基础矩阵乘上x次之后形成的矩阵(这里提下在上一条建树操作的时候数值为1的矩阵应该是单位矩阵,数值y大于等于1的存的应该是A[y-1]) 给区间数加上x就相当于给区间所有矩阵乘上一个A[x] 也即A[x]*(A[l]+A[l+1]+……+A[r]) 这样1操作可以用lazy的思想直接对整段进行更新

然后看操作2 我们只要对[l,r]中存的矩阵中[0][0]位置的数求和就是答案

注意:
线段树操作时所有的lazy,sum都用2*2的矩阵来存,并且lazy操作时矩阵是相乘而不是想加(本人在这儿错了好久)

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define PB push_back
#define MP make_pair
#define ll __int64
#define MS(a,b) memset(a,b,sizeof(a))
#define LL (rt<<1)
#define RR (rt<<1|1)
#define lson l,mid,LL
#define rson mid+1,r,RR
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lb(x) (x&(-x))
using namespace std;
void In(){freopen("in.in","r",stdin);}
void Out(){freopen("out.out","w",stdout);}
const int N=1e5+10;
const int M=1e6+10;
const int Mbit=1e6+10;
const int inf=0x3f3f3f3f;
const ll mod=1e9+7;
struct Matrix
{
ll mat[2][2];
int n;
Matrix(){}
Matrix(int _n)
{
n=_n;
for(int i=0;i<n;i++)for(int j=0;j<n;j++)mat[i][j]=0;
}
void zero(int _n)
{
n=_n;
for(int i=0;i<n;i++)for(int j=0;j<n;j++)mat[i][j]=0;
}
void unit(int _n)
{
n=_n;
for(int i=0;i<n;i++)for(int j=0;j<n;j++)mat[i][j]=(i==j);
}
Matrix operator +(const Matrix &b)const
{
Matrix ret=Matrix(n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
ret.mat[i][j]=(mat[i][j]+b.mat[i][j])%mod;
return ret;
}
Matrix operator *(const Matrix &b)const
{
Matrix ret = Matrix(n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int k=0;k<n;k++)
(ret.mat[i][j]+=mat[i][k]*b.mat[k][j])%=mod;
return ret;
}
};
Matrix mul(Matrix s,int n)
{
Matrix ans;
ans.unit(s.n);
while(n){
if(n&1)ans=ans*s;
s=s*s;
n>>=1;
}
return ans;
}
struct node
{
Matrix lazy,sum;
bool flag;
}tree[N<<2];
Matrix fibo(int x)
{
Matrix s;
s.n=2;
s.mat[0][0]=1;s.mat[0][1]=1;
s.mat[1][0]=1;s.mat[1][1]=0;
return mul(s,x-1);
}
Matrix fibo1(int x)
{
Matrix s;
s.n=2;
s.mat[0][0]=1;s.mat[0][1]=1;
s.mat[1][0]=1;s.mat[1][1]=0;
return mul(s,x);
}
void up(int rt)
{
tree[rt].sum=tree[LL].sum+tree[RR].sum;
}
void down(int rt)
{
if(tree[rt].flag){
tree[LL].lazy=tree[LL].lazy*tree[rt].lazy;
tree[RR].lazy=tree[RR].lazy*tree[rt].lazy;
tree[LL].sum=tree[LL].sum*tree[rt].lazy;
tree[RR].sum=tree[RR].sum*tree[rt].lazy;
tree[LL].flag=tree[RR].flag=1;
tree[rt].flag=0;tree[rt].lazy.unit(2);
}
}
void build(int l,int r,int rt)
{
if(l==r){
int x;scanf("%d",&x);
tree[rt].sum=fibo(x);
tree[rt].lazy.unit(2);
tree[rt].flag=0;
return;
}
tree[rt].sum.zero(2);
tree[rt].lazy.unit(2);
tree[rt].flag=0;
int mid=(l+r)>>1;
build(lson);
build(rson);
up(rt);
}
void update(int L,int R,int l,int r,int rt,Matrix x)
{
if(L<=l&&r<=R){
tree[rt].lazy=tree[rt].lazy*x;
tree[rt].flag=1;
tree[rt].sum=tree[rt].sum*x;
return;
}
down(rt);
int mid=(l+r)/2;
if(L<=mid) update(L,R,lson,x);
if(R>mid) update(L,R,rson,x);
up(rt);
}
ll query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)return tree[rt].sum.mat[0][0];
int mid=(l+r)/2;
down(rt);
ll ans=0;
if(L<=mid)ans+=query(L,R,lson);
if(R>mid) ans+=query(L,R,rson);
up(rt);
return ans%mod;
}
int main()
{
int n,m,op,l,r,x;
while(~scanf("%d%d",&n,&m)){
build(1,n,1);
while(m--){
scanf("%d%d%d",&op,&l,&r);
if(op==1){
scanf("%d",&x);
update(l,r,1,n,1,fibo(1+x));
}
else printf("%I64d\n",query(l,r,1,n,1));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐