CF718C Sasha and Array(线段树维护矩阵)

题解

(不会矩阵加速的先去学矩阵加速)

反正我想不到线段树维护矩阵。我太菜了。

我们在线段树上维护一个区间的斐波那契的列矩阵的和。

然后询问时提取每个符合题意列矩阵的答案项(不是列矩阵存了两项吗,一个是当前项,一个是用来递推的)

因为矩阵乘有结合律所以区间加这个操作就直接区间乘变换矩阵的x次方就行。

然后记得开long long

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 const long long mod=1e9+7;
  8 const long long N=100100;
  9 long long n,m;
 10 struct jz{
 11     long long a[3][3];
 12 }e,h,be,f[N],ma;
 13 struct tree{
 14     long long l,r;
 15     jz sum,lazy;
 16 }tr[N*5];
 17 jz jzc(jz a,jz b,jz c){
 18     for(long long i=1;i<=2;i++)
 19         for(long long j=1;j<=2;j++)
 20             for(long long k=1;k<=2;k++){
 21                 c.a[i][j]+=a.a[i][k]*b.a[k][j];
 22                 c.a[i][j]%=mod;
 23             }
 24     return c;
 25 }
 26 jz ksm(long long b,jz x){
 27     jz ans;
 28     ans=ma;
 29     while(b){
 30         if(b&1){
 31             ans=jzc(ans,x,h);
 32         }
 33         b>>=1;
 34         x=jzc(x,x,h);
 35     }
 36     return ans;
 37 }
 38 void update(long long now){
 39     tr[now].sum.a[1][1]=(tr[now*2].sum.a[1][1]+tr[now*2+1].sum.a[1][1])%mod;
 40     tr[now].sum.a[1][2]=(tr[now*2].sum.a[1][2]+tr[now*2+1].sum.a[1][2])%mod;
 41 }
 42 void build(long long l,long long r,long long now){
 43     tr[now].l=l;tr[now].r=r;tr[now].lazy=ma;
 44     if(l==r){
 45         tr[now].sum=f[l];
 46         return;
 47     }
 48     long long mid=(l+r)>>1;
 49     build(l,mid,now*2);
 50     build(mid+1,r,now*2+1);
 51     update(now);
 52 }
 53 bool pd(jz a,jz b){
 54     for(long long i=1;i<=2;i++)
 55         for(long long j=1;j<=2;j++)
 56             if(a.a[i][j]!=b.a[i][j])return false;
 57     return true;
 58 }
 59 void pushdown(long long now){
 60     if(pd(tr[now].lazy,ma))return;
 61     tr[now*2].sum=jzc(tr[now*2].sum,tr[now].lazy,h);
 62     tr[now*2+1].sum=jzc(tr[now*2+1].sum,tr[now].lazy,h);
 63     tr[now*2].lazy=jzc(tr[now*2].lazy,tr[now].lazy,h);
 64     tr[now*2+1].lazy=jzc(tr[now*2+1].lazy,tr[now].lazy,h);
 65     tr[now].lazy=ma;
 66 }
 67 void add(long long l,long long r,long long now,jz x){
 68     pushdown(now);
 69     if(tr[now].l==l&&tr[now].r==r){
 70         tr[now].sum=jzc(tr[now].sum,x,h);
 71         tr[now].lazy=x;
 72         return;
 73     }
 74     long long mid=(tr[now].l+tr[now].r)>>1;
 75     if(l>mid)add(l,r,now*2+1,x);
 76     else if(r<=mid)add(l,r,now*2,x);
 77     else{
 78         add(l,mid,now*2,x);
 79         add(mid+1,r,now*2+1,x);
 80     }
 81     update(now);
 82 }
 83 long long query(long long l,long long r,long long now){
 84     pushdown(now);
 85     if(tr[now].l==l&&tr[now].r==r){
 86         return tr[now].sum.a[1][2];
 87     }
 88     long long mid=(tr[now].l+tr[now].r)>>1;
 89     if(l>mid)return query(l,r,now*2+1);
 90     else if(r<=mid)return query(l,r,now*2);
 91     else return (query(l,mid,now*2)+query(mid+1,r,now*2+1))%mod;
 92 }
 93 int main(){
 94     scanf("%lld%lld",&n,&m);
 95     e.a[1][1]=0;e.a[1][2]=e.a[2][1]=e.a[2][2]=1;
 96     be.a[1][1]=0;be.a[1][2]=1;
 97     for(long long i=1;i<=2;i++)
 98         for(long long j=1;j<=2;j++)
 99             if(i==j)ma.a[i][j]=1;
100             else ma.a[i][j]=0;
101     for(long long i=1;i<=n;i++){
102         long long x;
103         scanf("%lld",&x);
104         if(x==1)f[i]=be;
105         else f[i]=jzc(be,ksm(x-1,e),h);
106     }
107     build(1,n,1);
108     for(long long i=1;i<=m;i++){
109         long long k;
110         scanf("%lld",&k);
111         if(k==1){
112             long long l,r,x;
113             scanf("%lld%lld%lld",&l,&r,&x);
114             add(l,r,1,ksm(x,e));
115         }
116         else{
117             long long l,r;
118             scanf("%lld%lld",&l,&r);
119             printf("%lld\n",query(l,r,1));
120         }
121     }
122     return 0;
123 }

原文地址:https://www.cnblogs.com/Xu-daxia/p/9403450.html

时间: 2024-10-10 21:10:41

CF718C Sasha and Array(线段树维护矩阵)的相关文章

codeforces CF718C Sasha and Array 线段树维护矩阵

$ \Rightarrow $ 戳我进CF原题 C. Underground Lab time limit per test: 1 second memory limit per test: 256 megabytes input: standard input output: standard output The evil Bumbershoot corporation produces clones for gruesome experiments in a vast undergroun

CF719E. Sasha and Array [线段树维护矩阵]

CF719E. Sasha and Array 题意: 对长度为 n 的数列进行 m 次操作, 操作为: a[l..r] 每一项都加一个常数 C, 其中 0 ≤ C ≤ 10^9 求 F[a[l]]+F[a[l+1]]+...F[a[r]] mod 1e9+7 的余数 矩阵快速幂求斐波那契 矩阵满足乘法分配律和结合律! 所以可以每个节点维护矩阵/矩阵和,区间加相当于区间乘矩阵 注意:不要把快速幂写在里面,复杂度平添一个log.把\(B^C\)算出来之后传进去就好了 #include <iostr

Subsequence Count 2017ccpc网络赛 1006 dp+线段树维护矩阵

Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string.There are two types of queries:1. Flipping the bits (i.e., changing all 1 to 0 and 0 to 1) between l and r (inclusive).2. Counting the

HDU 6155 Subsequence Count 线段树维护矩阵

Subsequence Count Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 256000/256000 K (Java/Others) Problem Description Given a binary string S[1,...,N] (i.e. a sequence of 0's and 1's), and Q queries on the string. There are two types of querie

[动态dp]线段树维护转移矩阵

背景:czy上课讲了新知识,从未见到过,总结一下. 所谓动态dp,是在动态规划的基础上,需要维护一些修改操作的算法. 这类题目分为如下三个步骤:(都是对于常系数齐次递推问题) 1先不考虑修改,不考虑区间,直接列出整个区间的dp方程.这个是基础,动态dp无论如何还是dp(这一步是一般是重点) 2.列出转移矩阵.由于有很多修改操作,我们将数据集中在一起处理,还可以利用矩阵结合律,并且区间比较好提取,(找一段矩阵就好了),修改也方便. 3.线段树维护矩阵.对于修改,我们就是在矩阵上进行修改,对于不同的

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 )

HDU 5068 Harry And Math Teacher( 矩阵乘法 + 线段树维护 ) 题意: 首先是这题题意理解错误,,其次是这题无法理解状态... 已经不是英文有多烂的情况了,是中文没学好啊.....大学不学语文才是真正的硬伤啊 题目意思 有一个城堡有很多层楼, 每层楼有2个门,每个门里面又有两个楼梯,可以通往上一层的两个门 问,从x层楼到y层楼有多少中方法(不能返回) 具体看图吧,,,已经不会说话了 1 #include <cstdio> 2 #include <cstri

2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数

肯定先无脑树链剖分,然后线段树维护一段区间不同个数,再维护一个左右端点的费用. 线段树更新,pushDown,pushUp的时候要注意考虑链接位置的费用是否相同 还有就是树链剖分操作的时候,维护上一个更新的位置的费用. 总之就是出现区间合并,就考虑总数是否要减一 好想不好写 //场上根本写不完啊 1 /*--------------------------------------------------------------------------------------*/ 2 3 #inc

Codeforces 482B Interesting Array(线段树)

题目链接:Codeforces 482B Interesting Array 题目大意:给定一个长度为N的数组,现在有M个限制,每个限制有l,r,q,表示从a[l]~a[r]取且后的数一定为q,问是 否有满足的数列. 解题思路:线段树维护,每条限制等于是对l~r之间的数或上q(取且的性质,相应二进制位一定为1),那么处理完所有的 限制,在进行查询,查询对应每个l~r之间的数取且是否还等于q.所以用线段树维护取且和,修改为或操作. #include <cstdio> #include <c

从《楼房重建》出发浅谈一类使用线段树维护前缀最大值的算法

首先需要申明的是,真的是浅谈,因为我对这个算法的认识还是非常低的. 既然是从<楼房重建>出发,那么当然是先看看这道题: [清华集训2013]楼房重建 bzoj 链接 题意简述: 有 \(n\) 栋楼,第 \(i\) 栋的高度为 \(H_i\),也就是说第 \(i\) 栋楼可以抽象成一条两端点为 \((i, 0)\) 和 \((i, H_i)\) 的线段. 初始时 \(H_i\) 均为 \(0\),要支持动态修改单点的 \(H_i\). 每次询问从 \(O(0, 0)\) 点可以看到多少栋楼房.