ABBYY Cup 3.0 E3

来源:互联网 发布:数据库设计实例 教材 编辑:程序博客网 时间:2024/04/18 08:27

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 longconst 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 , 1struct 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) ;            }        }    }}
原创粉丝点击