传送门

一道纯粹的码力 + 卡常题。

前置

矩阵乘法,线段树。

分析

线段树存矩阵。

构造迭代矩阵:

\[\begin{pmatrix}f_i&f_{i-1}\end{pmatrix}\times\begin{pmatrix}1&1\\1&0\end{pmatrix}=\begin{pmatrix}f_{i+1}&f_{i}\end{pmatrix}
\]
\[\begin{pmatrix}f_i&f_{i-1}\end{pmatrix}\times\begin{pmatrix}0&1\\1&-1\end{pmatrix}=\begin{pmatrix}f_{i-1}&f_{i-2}\end{pmatrix}
\]

另外矩阵乘法满足分配律,于是父结点矩阵为子结点矩阵之和。

然后就很清楚了。

先把要用的矩阵处理出来。

\(add\) 操作就是直接乘。

\(set\) 操作就直接覆盖即可。

两个标记 \(add\) 和 \(set\),维护一下即可。

卡常

能用位运算尽量位运算。

快速幂不要递归求。

存矩阵不要用 \(a[2][2]\),用 \(a,b,c,d\) 分别表示矩阵的四项。

\(a,b,c,d\) 不要开 \(longlong\),考虑取模 \(10^9+7\),矩阵加法不会溢出,矩阵乘法先转 \(longlong\) 再取模,要快很多。

Code

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
#define ri register int
const int N = 5e5 + 10, MOD = 1e9 + 7; inline LL read () {
LL num = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') num = num * 10 + (c ^ 48), c = getchar();
return num * f;
} int mod (int x) {
return (x % MOD + MOD) % MOD;
} struct matrix {
int a, b, c, d;
void clear () {
a = b = c = d = 0;
}
friend matrix operator + (const matrix &x, const matrix &y) {
matrix ans;
ans.a = mod(x.a + y.a);
ans.b = mod(x.b + y.b);
ans.c = mod(x.c + y.c);
ans.d = mod(x.d + y.d);
return ans;
}
friend matrix operator * (const matrix &x, const matrix &y) {
matrix ans;
ans.a = mod(1ll * x.a * y.a % MOD + 1ll * x.b * y.c % MOD);
ans.b = mod(1ll * x.a * y.b % MOD + 1ll * x.b * y.d % MOD);
ans.c = mod(1ll * x.c * y.a % MOD + 1ll * x.d * y.c % MOD);
ans.d = mod(1ll * x.c * y.b % MOD + 1ll * x.d * y.d % MOD);
return ans;
}
}; const matrix st = (matrix){1, 0, 0, 1}, fibnxt = (matrix){1, 1, 1, 0}, fib = (matrix){1, 1, 0, 0}, fibpre = (matrix){0, 1, 1, -1}; matrix mat_qpow (matrix x, LL b) {
matrix res = st;
while (b) {
if (b & 1) res = res * x;
b >>= 1; x = x * x;
}
return res;
} int n, m;
LL a[N]; struct node {
int l, r, cset;
matrix mat, add, sett;
}tree[N << 2]; inline void push_up (int p) {
tree[p].mat = tree[p << 1].mat + tree[p << 1 | 1].mat;
} inline void update (int p, matrix x) {
if (!tree[p].cset) tree[p].add = tree[p].add * x;
else tree[p].sett = tree[p].sett * x;
tree[p].mat = tree[p].mat * x;
return;
} inline void push_down (int p) {
if (tree[p].cset) {
int ll = tree[p << 1].r - tree[p << 1].l + 1; int lr = tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1;
tree[p << 1].add = tree[p << 1 | 1].add = st;
tree[p << 1].sett = tree[p << 1 | 1].sett = tree[p].sett;
tree[p << 1].mat = (matrix){ll, 0, 0, ll} * tree[p].sett;
tree[p << 1 | 1].mat = (matrix){lr, 0, 0, lr} * tree[p].sett;
tree[p << 1].cset = tree[p << 1 | 1].cset = 1;
tree[p].cset = 0;
}
else {
update(p << 1, tree[p].add); update(p << 1 | 1, tree[p].add);
tree[p].add = st;
}
} void build (int p, int l, int r) {
tree[p].l = l, tree[p].r = r; tree[p].add = st;
if (l == r) {
tree[p].mat = fib * mat_qpow(fibnxt, a[l] - 1);
return;
}
int mid = (l + r) >> 1;
build (p << 1, l, mid); build (p << 1 | 1, mid + 1, r);
push_up(p);
} void add (int p, int l, int r, matrix x) {
int tl = tree[p].l, tr = tree[p].r;
if (tl >= l && tr <= r) {
update(p, x);
return;
}
push_down(p);
int mid = (tl + tr) >> 1;
if (l <= mid) add (p << 1, l, r, x);
if (r > mid) add (p << 1 | 1, l, r, x);
push_up(p);
} void sett (int p, int l, int r, matrix x) {
int tl = tree[p].l, tr = tree[p].r;
if (tl >= l && tr <= r) {
tree[p].cset = 1;
int ll = tr - tl + 1;
tree[p].mat = (matrix){ll, 0, 0, ll} * x;
tree[p].sett = x;
tree[p].add = st;
return;
}
push_down(p);
int mid = (tl + tr) >> 1;
if (l <= mid) sett (p << 1, l, r, x);
if (r > mid) sett (p << 1 | 1, l, r, x);
push_up(p);
} int stk[N << 4], ed; matrix query (int p, int l, int r) {
int tl = tree[p].l, tr = tree[p].r;
if (tl >= l && tr <= r) return tree[p].mat;
push_down(p);
int mid = (tl + tr) >> 1;
matrix res; res.clear();
if (l <= mid) res = res + query (p << 1, l, r);
if (r > mid) res = res + query (p << 1 | 1, l, r);
return res;
} int main () {
// freopen("data10.in", "r", stdin);
// freopen("data10.ans", "w", stdout);
n = read();
for (ri i = 1;i <= n;++i) a[i] = read();
build (1, 1, n);
m = read();
while (m--) {
int op = read(), l = read(), r = read(), x;
if (op == 1) {
x = read();
matrix mat;
if (x < 0) mat = mat_qpow(fibpre, -x);
else mat = mat_qpow(fibnxt, x);
add(1, l, r, mat);
}
else if (op == 2) {
x = read();
matrix mat = fib * mat_qpow(fibnxt, x - 1);
sett(1, l, r, mat);
}
else printf("%lld\n", query(1, l, r).b);
}
return 0;
}

U268603 I Hate This Tree 题解的更多相关文章

  1. Codeforces Round #530 (Div. 2):D. Sum in the tree (题解)

    D. Sum in the tree 题目链接:https://codeforces.com/contest/1099/problem/D 题意: 给出一棵树,以及每个点的si,这里的si代表从i号结 ...

  2. POJ 1308 Is It A Tree?--题解报告

    Is It A Tree? Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 31092   Accepted: 10549 D ...

  3. C++版 - 剑指offer 面试题39:判断平衡二叉树(LeetCode 110. Balanced Binary Tree) 题解

    剑指offer 面试题39:判断平衡二叉树 提交网址:  http://www.nowcoder.com/practice/8b3b95850edb4115918ecebdf1b4d222?tpId= ...

  4. 【文文殿下】CF1098C Construct a tree 题解

    题解 挺水的一道题. Rating $ \color{orange} {2300}$ 以下送命题. 首先我们知道,所有子树大小之和就是节点个数加上从根到所有节点的路径长度之和. 他要求度数尽可能小,所 ...

  5. BZOJ2588:Count on a tree——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=2588 Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你 ...

  6. CC TSUBSTR:Substrings on a Tree——题解

    https://www.codechef.com/problems/TSUBSTR https://vjudge.net/problem/CodeChef-TSUBSTR 给一棵点权为字母的树,你只能 ...

  7. 【日常学习】【二叉树遍历】Uva548 - Tree题解

    这道题目本身不难,给出后序遍历和中序遍历,求到节点最小路径的叶子,同样长度就输出权值小的叶子. Uva上不去了,没法測.基本上是依照ruka的代码来的.直接上代码 //Uva548 Tree #inc ...

  8. SPOJ - QTREE Query on a tree题解

    题目大意: 一棵树,有边权,有两个操作:1.修改一条边的权值:2.询问两点间路径上的边的权值的最大值. 思路: 十分裸的树链剖分+线段树,无非是边权要放到深度大的一端的点上,但是有两个坑爹的地方,改了 ...

  9. 洛谷 P2633 Count on a tree 题解

    题面 对于每个点建立一颗主席树: 然后按照树上差分的思想统计主席树的前缀和: lca+主席树+前向星存表就可以了: #include <bits/stdc++.h> #define inc ...

  10. [Luogu P4178]Tree 题解(点分治+平衡树)

    题目大意 给定一棵树,边带权,问有多少点对满足二者间距离$\leq K$,$n \leq 40000$. 题解 点分治专题首杀!$Jackpot!$ (本来看着题意比较简单想捡个软柿子捏,结果手断了… ...

随机推荐

  1. 2022-05-03:Alice 和 Bob 再次设计了一款新的石子游戏。现有一行 n 个石子,每个石子都有一个关联的数字表示它的价值。给你一个整数数组 stones ,其中 stones[i] 是第

    2022-05-03:Alice 和 Bob 再次设计了一款新的石子游戏.现有一行 n 个石子,每个石子都有一个关联的数字表示它的价值.给你一个整数数组 stones ,其中 stones[i] 是第 ...

  2. 2021-07-06:股票问题3。给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。注意:你不能同时参与多笔交易(

    2021-07-06:股票问题3.给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格.设计一个算法来计算你所能获取的最大利润.你最多可以完成 两笔 交易.注意:你不能同时参与多笔交易( ...

  3. 【GiraKoo】面向对象开发系列之【为什么要用面向对象】

    开源项目:https://girakoo.com/ 问答 为什么要有面向对象开发? 面向过程开发的C语言,往往有以下几个问题: 不同的开发人员需要使用功能完全相同,或者大部分相同的函数.如果某个算法存 ...

  4. 3 分钟利用 FastGPT 和 Laf 将 ChatGPT 接入企业微信

    原文链接:https://forum.laf.run/d/556 FastGPT 是一个超级的 ChatGPT 平台项目,功能非常强大: 集成了 ChatGPT.GPT4 和 Claude 可以使用任 ...

  5. .Net8顶级技术:边界检查之IR解析(慎入)

    前言 C#这种语言之所以号称安全的,面向对象的语言.这个安全两个字可不是瞎叫的哦.因为JIT会检查任何可能超出分配范围的数值,以便使其保持在安全边界内.这里有两个概念,其一边界检查,其二IR解析.后者 ...

  6. [abc279 G] At Most 2 Colors

    G - At Most 2 Colors (atcoder.jp) 重点讲解方法三,因为方法三是蒟蒻都能想出来的方法一和方法二都可以借助方法三的思想推出 方法一 这是最简单的设置状态的方法,\(dp[ ...

  7. R 语言中 X11 相关的一些问题

    参考 Anaconda 官方文档<Using R language with Anaconda>安装 R-4.0.2: conda create -n r-4.0.2 r-essentia ...

  8. 网站开发[1] - Spring Boot 快速建立项目

    前言 学校的数据库课程要求做出前端页面对数据库进行交互, 可以使用 Python 或者 Java 语言作为后端, Python语言使用起来非常方便, 但出于对自己的挑战以及更加贴合实际企业开发, 我选 ...

  9. 【可视化大屏】用Python开发「淄博烧烤」微博热评舆情分析大屏

    目录 一.开发背景 二.爬虫代码 2.1 爬微博列表 2.2 爬微博评论 2.3 导入MySQL数据库 三.可视化代码 3.1 大标题 3.2 词云图(含:加载停用词) 3.3 玫瑰图(含:snown ...

  10. 区块链的Token机制如何理解?

    区块链的Token机制如何理解? 为了更好的理解区块链和Token的关系,今天专门基于互联网中的内容,做了下筛选过滤,从而可以让大家更好的理解,对于Token,如果是从事过开发的同学来说,比如容易理解 ...