Codeforces 719E (线段树教做人系列) 线段树维护矩阵
题面简洁明了,一看就懂
做了这个题之后,才知道怎么用线段树维护递推式。递推式的递推过程可以看作两个矩阵相乘,假设矩阵A是初始值矩阵,矩阵B是变换矩阵,求第n项相当于把矩阵B乘了n - 1次。
那么我们线段树中每个点维护把矩阵B乘了多少次,懒标记下放的时候用快速幂维护sum。
#include <bits/stdc++.h>
#define LL long long
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
using namespace std;
const LL mod = 1000000007;
const int maxn = 100010;
struct Matrix {
static const int len = 2;
LL x[len][len]; void init() {
memset(x, 0, sizeof(x));
for (int i = 0; i < len; i++)
x[i][i] = 1;
} void zero() {
memset(x, 0, sizeof(x));
} Matrix operator * (const Matrix& m) const {
Matrix ans;
ans.zero();
for (int i = 0; i < len; i++)
for (int j = 0; j < len; j++)
for (int k = 0; k < len; k++)
ans.x[i][j] = (ans.x[i][j] + x[i][k] * m.x[k][j]) % mod;
return ans;
} Matrix operator + (const Matrix& m) const {
Matrix ans;
ans.zero();
for (int i = 0; i < len; i++)
for (int j = 0; j < len; j++)
ans.x[i][j] = (x[i][j] + m.x[i][j]) % mod;
return ans;
} Matrix operator ^ (int b) const {
Matrix ans, a;
ans.init();
memcpy(a.x, x, sizeof(x));
for (; b; b >>= 1) {
if(b & 1) ans = ans * a;
a = a * a;
}
return ans;
}
}; Matrix mul , tmp, trans ;
int a[maxn];
struct SegementTree {
int lz;
Matrix sum, flag;
}; SegementTree tr[maxn * 4]; void maintain(int o) {
tr[o].sum = tr[ls(o)].sum + tr[rs(o)].sum;
} void pushdown(int o) {
if(tr[o].lz) {
tr[ls(o)].sum = tr[ls(o)].sum * tr[o].flag;
tr[rs(o)].sum = tr[rs(o)].sum * tr[o].flag;
tr[ls(o)].flag = tr[ls(o)].flag * tr[o].flag;
tr[rs(o)].flag = tr[rs(o)].flag * tr[o].flag;
tr[o].lz = 0;
tr[ls(o)].lz = 1;
tr[rs(o)].lz = 1;
tr[o].flag.init();
}
} void build(int o, int l, int r) {
tr[o].sum.zero();
tr[o].lz = 0;
tr[o].flag.init();
if(l == r) {
tr[o].sum = trans * ( mul ^ (a[l] - 1));
return;
}
int mid = (l + r) >> 1;
build(ls(o), l, mid);
build(rs(o), mid + 1, r);
maintain(o);
} void update(int o, int l, int r, int ql, int qr, Matrix now) {
if(l >= ql && r <= qr) {
tr[o].sum = tr[o].sum * now;
tr[o].flag = tr[o].flag * now;
tr[o].lz = 1;
return;
}
pushdown(o);
int mid = (l + r) >> 1;
if(ql <= mid) update(ls(o), l, mid, ql, qr, now);
if(qr > mid) update(rs(o), mid + 1, r, ql, qr, now);
maintain(o);
} LL query(int o, int l, int r, int ql, int qr) {
if(l >= ql && r <= qr) {
return tr[o].sum.x[0][1];
}
pushdown(o);
int mid = (l + r) >> 1;
LL ans = 0;
if(ql <= mid) ans = (ans + query(ls(o), l, mid, ql, qr)) % mod;
if(qr > mid) ans = (ans + query(rs(o), mid + 1, r, ql, qr)) % mod;
return ans;
} int main() {
int n, m, op, l, r;
LL x;
trans.zero();
trans.x[0][1] = 1;
mul.x[0][1] = mul.x[1][0] = mul.x[1][1] = 1;
mul.x[0][0] = 0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
build(1, 1, n);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &op, &l, &r);
if(op == 1) {
scanf("%lld", &x);
tmp = (mul ^ x);
update(1, 1, n, l, r, tmp);
} else {
printf("%lld\n", query(1, 1, n, l, r));
}
}
}
Codeforces 719E (线段树教做人系列) 线段树维护矩阵的更多相关文章
- Codeforces 1136E Nastya Hasn't Written a Legend (线段树教做人系列)
题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后, ...
- 线段树教做人系列(2)HDU 4867 XOR
题意:给你一个数组a,长度为.有两种操作.一种是改变数组的某个元素的值,一种是满足某种条件的数组b有多少种.条件是:b[i] <= a[i],并且b[1]^b[2]...^b[n] = k的数组 ...
- 线段树教做人系列(1)HDU4967 Handling the Past
题意:给你n组操作,分别为压栈,出栈,询问栈顶元素.每一组操作有一个时间戳,每次询问栈顶的元素的操作询问的是在他之前出现的操作,而且时间戳小于它的情况.题目中不会出现栈为空而且出栈的情况. 例如: p ...
- 线段树教做人系列(3) HDU 4913
题意及思路看这篇博客就行了,讲得很详细. 下面是我自己的理解: 如果只有2,没有3的话,做法就很简单了,只需要对数组排个序,然后从小到大枚举最大的那个数.那么它对答案的贡献为(假设这个数排序后的位置是 ...
- Codeforces 750E New Year and Old Subsequence - 线段树 - 动态规划
A string t is called nice if a string "2017" occurs in t as a subsequence but a string &qu ...
- Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+ 树状数组或线段树
C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...
- Codeforces 1063F - String Journey(后缀数组+线段树+dp)
Codeforces 题面传送门 & 洛谷题面传送门 神仙题,做了我整整 2.5h,写篇题解纪念下逝去的中午 后排膜拜 1 年前就独立切掉此题的 ymx,我在 2021 年的第 5270 个小 ...
- Codeforces 1368H - Breadboard Capacity(最小割+线段树维护矩阵乘法)
Easy version:Codeforces 题面传送门 & 洛谷题面传送门 Hard version:Codeforces 题面传送门 & 洛谷题面传送门 首先看到这种从某一种颜色 ...
- Codeforces 750E - New Year and Old Subsequence(线段树维护矩阵乘法,板子题)
Codeforces 题目传送门 & 洛谷题目传送门 u1s1 我做这道 *2600 的动力是 wjz 出了道这个套路的题,而我连起码的思路都没有,wtcl/kk 首先考虑怎样对某个固定的串计 ...
随机推荐
- 代码题 — 剑指offer题目、新增题目
1.剪绳子 给你一根长度为n的绳子,请把绳子剪成m段 (m和n都是整数,n>1并且m>1)每段绳子的长度记为k[0],k[1],...,k[m].请问k[0]*k[1]*...*k[m] ...
- python中利用正则表达式匹配ip地址
现在有一道题目,要求利用python中re模块来匹配ip地址,我们应如何着手? 首先能想到的是ip地址是数字,正则表达式是如何匹配数字的呢? \d或[0-9] 对于这个问题,不要一下子上来就写匹配模式 ...
- hdu 5237 Base64(模拟)
Base64 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Subm ...
- 原生MapReduce开发样例
一.需求 data: 将相同名字合并为一个,并计算出平均数 tom 小明 jerry 2哈 tom tom 小明 二.编码 1.导入jar包 2.编码 2.1Map编写 package com.wzy ...
- hdoj-1285-确定比赛名次(拓扑排序)
题目链接 /* Name:hdoj-1285-确定比赛名次 Copyright: Author: Date: 2018/4/11 15:59:18 Description: 标准的拓扑排序模板题,注意 ...
- 基于Seajs的可控台球碰撞游戏
前言 不记得哪个黑色星期五,贪吃鱼基本完工的时候,产品突然增加需求,要求金币扔出去后不消失,互相可碰撞,其最终结果还要由服务器控制(没错,至今做的所有游戏都有幕后黑手,=W=). 对于碰撞以前只写过一 ...
- C# WebApi 配置复杂路由不生效的问题
配置复杂路由不生效是由于优先级的关系,应该把默认路由放在最后. config.Routes.MapHttpRoute( name: "DynamicApi", routeTempl ...
- BZOJ5118:Fib数列2(O1快速模)
题意:输入N,输出fib(2^N)%1125899839733759.(P=1125899839733759是素数) 思路:欧拉降幂,因为可以表示为矩阵乘法,2^N在幂的位置,矩阵乘法也可以降幂,所以 ...
- 洛谷 P3904 三只小猪
题目背景 你听说过三只小猪的故事吗?这是一个经典的故事.很久很久以前,有三只小猪.第一只小猪用稻草建的房子,第二个小猪用木棍建的房子,第三个小猪则使用砖做为材料.一只大灰狼想吃掉它们并吹倒了稻草和木棍 ...
- 学习动态性能表(22)V$resource_limit
学习动态性能表 第20篇--V$resource_limit 2007.6.15 就一条SQL语句供你参考: select * from V$RESOURCE_LIMIT where resourc ...