ABBYY Cup 3.0 E3

9 篇文章 0 订阅
2 篇文章 0 订阅

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) ;
            }
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值