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

题意:

给你一个数列,有两种操作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
#include
#include
#include
#include
#include
#include
#include
#include
#include
#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
#define pll pair
#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>=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;
}


你可能感兴趣的:(ACM)