CF719E(线段树+矩阵快速幂)
题意:给你一个数列a,a[i]表示斐波那契数列的下标为a[i],求区间对应斐波那契数列数字的和,还要求能够维护对区间内所有下标加d的操作
分析:线段树
线段树的每个节点表示(f[i],f[i-1])这个数组
因为矩阵的可加性,所以可以进行lazy操作
我最开始的想法是每个节点lazy表示该区间下标加了多少,add表示该区间已经加的下标对应的矩阵乘积,这样更新lazy是O(1)的,算add是O(logn)的
但是这样每次pushdown的时候,add下传总要多个log,会TLE
更好的办法是lazy表示加的下标对应的矩阵乘积,这样虽然每次更新lazy是O(logn)的,但是pushdown的时候就是直接把(f[i],f[i-1])和lazy[2][2]乘起来了,是O(1)的
代码:
- #include<bits/stdc++.h>
- const int maxn=1e5;
- const long long mod=1e9+;
- int ch[maxn*+][];
- long long sum[maxn*+][],add[maxn*+][][],a[maxn+];
- int len=,n,m;
- void mer(long long a[][],long long b[][])
- {
- long long s[][];
- memset(s,,sizeof(s));
- for(int i=;i<;++i)
- for(int j=;j<;++j)
- for(int k=;k<;++k)
- s[i][j]=(s[i][j]+a[i][k]*b[k][j]%mod)%mod;
- for(int i=;i<;++i)
- for(int j=;j<;++j)
- a[i][j]=s[i][j];
- }
- void fib(long long num[][],long long x)
- {
- long long a[][]={{,},{,}};
- num[][]=,num[][]=,num[][]=,num[][]=;
- while(x)
- {
- if(x&) mer(num,a);
- mer(a,a);
- x>>=;
- }
- }
- void cal(long long sum[],long long s[][])
- {
- long long x=(sum[]*s[][]%mod+sum[]*s[][]%mod)%mod;
- long long y=(sum[]*s[][]%mod+sum[]*s[][]%mod)%mod;
- sum[]=x,sum[]=y;
- }
- void pushdown(int k)
- {
- if(add[k][][]==&&add[k][][]==&&add[k][][]==&&add[k][][]==) return;
- //printf("A");
- //cal(sum[k],add[k]);
- int l=ch[k][],r=ch[k][];
- if(l) mer(add[l],add[k]),cal(sum[l],add[k]);
- if(r) mer(add[r],add[k]),cal(sum[r],add[k]);
- add[k][][]=,add[k][][]=,add[k][][]=,add[k][][]=;
- }
- void update(int k)
- {
- int l=ch[k][],r=ch[k][];
- //cal(sum[k],add[k]);
- //pushdown(k);
- for(int i=;i<;++i) sum[k][i]=(sum[l][i]+sum[r][i])%mod;
- // if(k==2) printf("A : %d %d %lld %lld\n",l,r,sum[l][0],sum[r][0]);
- }
- int build(int l,int r)
- {
- if(l>r) return ;
- int mid=(l+r)>>;
- int k=++len;
- add[k][][]=,add[k][][]=,add[k][][]=,add[k][][]=;
- if(l==r)
- {
- sum[k][]=,sum[k][]=;
- long long num[][];
- fib(num,a[l]-);
- cal(sum[k],num);
- //printf("%d %d %d %d %d\n",l,r,k,ch[k][0],ch[k][1]);
- return k;
- }
- ch[k][]=build(l,mid);
- ch[k][]=build(mid+,r);
- update(k);
- return k;
- // printf("%d %d %d %d %d\n",l,r,k,ch[k][0],ch[k][1]);
- }
- void make(int k,int l,int r,int x,int y,long long num[][])
- {
- if(l>r) return;
- if(l>y||r<x) return;
- if(x<=l&&y>=r)
- {
- mer(add[k],num);
- cal(sum[k],num);
- return;
- }
- int mid=(l+r)>>;
- pushdown(k);
- if(l<=mid) make(ch[k][],l,mid,x,y,num);
- if(r>mid) make(ch[k][],mid+,r,x,y,num);
- update(k);
- }
- long long query(int k,int l,int r,int x,int y)
- {
- if(l>r) return ;
- if(l>y||r<x) return ;
- if(x<=l&&y>=r)
- {
- return sum[k][];
- }
- int mid=(l+r)>>;
- pushdown(k);
- return (query(ch[k][],l,mid,x,y)+query(ch[k][],mid+,r,x,y))%mod;
- }
- int main()
- {
- scanf("%d %d",&n,&m);
- for(int i=;i<=n;++i) scanf("%lld",&a[i]);
- build(,n);
- //for(int i=1;i<=len;++i) printf("%d %lld %lld\n",i,sum[i][0],sum[i][1]);
- //or(int i=1;i<=len;++i) printf("%d %lld %lld %lld %lld\n",i,add[i][0][0],add[i][0][1],add[i][1][0],add[i][1][1]);
- for(int i=;i<=m;++i)
- {
- int t,l,r;
- long long x;
- scanf("%d %d %d",&t,&l,&r);
- if(t==)
- {
- scanf("%lld",&x);
- long long num[][];
- fib(num,x);
- make(,,n,l,r,num);
- }
- else printf("%lld\n",query(,,n,l,r));
- }
- return ;
- }
CF719E(线段树+矩阵快速幂)的更多相关文章
- Wannafly Winter Camp 2019.Day 8 div1 E.Souls-like Game(线段树 矩阵快速幂)
题目链接 \(998244353\)写成\(99824435\)然后调这个线段树模板1.5h= = 以后要注意常量啊啊啊 \(Description\) 每个位置有一个\(3\times3\)的矩阵, ...
- 线段树+矩阵快速幂 Codeforces Round #373 (Div. 2) E
http://codeforces.com/contest/719/problem/E 题目大意:给你一串数组a,a[i]表示第i个斐波那契数列,有如下操作 ①对[l,r]区间+一个val ②求出[l ...
- CF575A Fibonotci [线段树+矩阵快速幂]
题意 \(s\{\}\) 是一个循环数列 循环节为 \(n\),你可以改掉 \(m\) 项,这 \(m\) 项独立,且不影响循环节 考虑线段树维护矩阵,单点修改最多m次,每次矩阵快速幂就完事了 // ...
- Codeforces 719E [斐波那契区间操作][矩阵快速幂][线段树区间更新]
/* 题意:给定一个长度为n的序列a. 两种操作: 1.给定区间l r 加上某个数x. 2.查询区间l r sigma(fib(ai)) fib代表斐波那契数列. 思路: 1.矩阵操作,由矩阵快速幂求 ...
- 【66测试20161115】【树】【DP_LIS】【SPFA】【同余最短路】【递推】【矩阵快速幂】
还有3天,今天考试又崩了.状态还没有调整过来... 第一题:小L的二叉树 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣.所以,小L当时卡在了二叉树. ...
- 【XSY2524】唯一神 状压DP 矩阵快速幂 FFT
题目大意 给你一个网格,每个格子有概率是\(1\)或是\(0\).告诉你每个点是\(0\)的概率,求\(1\)的连通块个数\(\bmod d=0\)的概率. 最开始所有格子的概率相等.有\(q\)次修 ...
- 培训补坑(day10:双指针扫描+矩阵快速幂)
这是一个神奇的课题,其实我觉得用一个词来形容这个算法挺合适的:暴力. 是啊,就是循环+暴力.没什么难的... 先来看一道裸题. 那么对于这道题,显然我们的暴力算法就是枚举区间的左右端点,然后通过前缀和 ...
- 【对不同形式矩阵的总结】WC 2009 最短路径问题(线段树+矩阵乘法)
题意 题目链接:https://www.luogu.org/problem/P4150 一个 \(6\times n\) 的网格图,每个格点有一个初始权值.有两种操作: 修改一个格子的权值 求 ...
- 【模板】矩阵快速幂 洛谷P2233 [HNOI2002]公交车路线
P2233 [HNOI2002]公交车路线 题目背景 在长沙城新建的环城公路上一共有8个公交站,分别为A.B.C.D.E.F.G.H.公共汽车只能够在相邻的两个公交站之间运行,因此你从某一个公交站到另 ...
随机推荐
- [Maven]Maven入门教程
概念 Maven是什么 Maven 是一个项目管理工具.它负责管理项目开发过程中的几乎所有的东西. 版本 maven有自己的版本定义和规则 构建 maven支持许多种的应用程序类型,对于每一种支持的应 ...
- Docker for Windows使用简介
在上一篇文章中,通过演练指导的方式,介绍了在Docker中运行ASP.NET Core Web API应用程序的过程.本文将介绍Docker for Windows的使用. 先决条件 前两周时间,Do ...
- JavaScript移除绑定在元素上的匿名事件处理函数
前言: 面试的时候有点蒙,结束之后想想自己好像根本就误解了面试官的问题,因为我理解的这个问题本身就没有意义.但是当时已经有一些思路,但是在一个点上被卡住. 结束之后脑子瞬间灵光,想出了当时没有迈出的那 ...
- oracle函数案例以及分页案例
--日期函数select sysdate from dual--返回两个日期select months_between(to_date('2017-1-7','yyyy-mm-dd'),to_date ...
- 精彩 JavaScript 代码片段
1. 根据给定的条件在原有的数组上,得到所需要的新数组. ——<JavaScript 王者归来> var a = [-1,-1,1,2,-2,-2,-3,-3,3,-3]; functio ...
- [.NET Core].NET Core R2安装教程及Hello示例
前言 前几天.NET Core发布了.NET Core 1.0.1 R2 预览版,之前想着有时间尝试下.NET Core.由于各种原因,就没有初试.刚好,前几天看到.NET Core发布新版本了,决定 ...
- 利用TortoiseSVN获取最新版本的OpenCV源码
转自: http://blog.csdn.net/vsooda/article/details/7555969 1.下载安装TortoiseSVN:http://tortoisesvn.net/dow ...
- PHP数组的基础知识
- java反射复制属性值
/** 将sourceObj的属性拷贝到targetObj * @param sourceObj * @param targetObj * @param clazz 从哪一个类开始(比如sourceO ...
- Consul的一个更新:服务端节点故障后重连
研究了一段时间Consul,想写个攻略来着,但太赖了而且表达能力非正常人...今天发现HashiCorp果然接纳大众意见改了点东西.. 场景是: 假如Consul集群内有三个Server Node 时 ...