CF633H (线段树维护矩乘 + 莫队)
Fibonacci-ish II
题意:给定一个长度最大为 \(30000\) 的序列,和最多 \(30000\) 个询问,每个询问问某区间 \([L,R]\) 里的数,去掉重复然后排序之后,依次乘上斐波那契数列然后求和,结果对 \(m\) 取余的值。
转化一下题意,也就是在值域数轴上求 \(\sum a_i \cdot b_i\)。
\(a_i\) 是当前位置的值,如果在询问区间中存在就为 \(val\),否则为 \(0\)。
\(b_i\) 是该位置乘的哪个斐波那契数。
考虑在 \(p\) 位置加入一个数,会产生什么变化。
- \(a_p = val\)
- \([p + 1, inf]\) 的所有 \(b\) 变为其下一项。
斐波那契有良好的性质。
1 & 1\\
1 & 0 \\
\end{matrix}
\right]^n =
\left[
\begin{matrix}
Fib_{n + 1} & Fib_n\\
Fib_n & Fib_{n - 1}
\end{matrix}
\right]
\]
所以操作二转化为 \([p + 1, inf]\) 所有 \(b\) 乘上 \(\left[ \begin{matrix} 1 & 1\\ 1 & 0 \\ \end{matrix} \right]\),用线段树维护。
每个节点的懒标记可以用矩阵维护,但常数太大。
只记录每个懒标记的次数,预处理 \(Fib[i]\) 和 \(invFiv[i]\) 来分别表示 \(\left[ \begin{matrix} 1 & 1\\ 1 & 0 \\ \end{matrix} \right]^i\) 和其逆 \(\left[ \begin{matrix} 0 & 1\\ 1 & -1 \\ \end{matrix} \right]^i\)。
为了减小常数,这里我用一维数组来实现矩阵。
#pragma GCC optimize("Ofast", "inline", "-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); ++ i)
#define per(i, a, b) for(int i = (a); i >= (b); -- i)
#define pb emplace_back
#define All(X) X.begin(), X.end()
using namespace std;
using ll = long long;
constexpr int N = 3e4 + 5, B = 175;
int n, m, P, Fib[N][4] = {1, 0, 0, 1}, invFib[N][4] = {1, 0, 0, 1};
int M[4] = {1, 1, 1, 0};
int invM[4] = {0, 1, 1, -1};
int c[4];
inline void mul(int a[4], int b[4]) {
c[0] = (a[0] * b[0] + a[1] * b[2]) % P;
c[1] = (a[0] * b[1] + a[1] * b[3]) % P;
c[2] = (a[2] * b[0] + a[3] * b[2]) % P;
c[3] = (a[3] * b[3] + a[2] * b[1]) % P;
memcpy(a, c, 16);
}
int a[N], b[N], tot;
int t[N << 2][4], val[N << 2], tag[N << 2];
#define ls x << 1
#define rs ls | 1
inline void pushup(int x) {
t[x][0] = (t[ls][0] * val[ls] + t[rs][0] * val[rs]) % P;
t[x][1] = (t[ls][1] * val[ls] + t[rs][1] * val[rs]) % P;
t[x][2] = (t[ls][2] * val[ls] + t[rs][2] * val[rs]) % P;
t[x][3] = (t[ls][3] * val[ls] + t[rs][3] * val[rs]) % P;
}
/*
由于 val 可能为 0,直接在叶子节点上操作有可能会丢失信息
因此把乘 val 的操作放在 pushup 中完成
*/
inline void pushdown(int x) {
if(tag[x]) {
if(tag[x] > 0) {
mul(t[ls], Fib[tag[x]]);
mul(t[rs], Fib[tag[x]]);
}
if(tag[x] < 0) {
mul(t[ls], invFib[-tag[x]]);
mul(t[rs], invFib[-tag[x]]);
}
tag[ls] += tag[x];
tag[rs] += tag[x];
tag[x] = 0;
}
}
void build(int x = 1, int l = 1, int r = tot) {
val[x] = l != r; //非叶子节点的 val 为 1
if(l == r) {
memcpy(t[x], M, 16);
return;
}
int mid = l + r >> 1;
build(ls, l, mid), build(rs, mid + 1, r);
}
inline void insert(int p, int x = 1, int l = 1, int r = tot) {
if(l == r) return val[x] = b[p], void();
pushdown(x);
int mid = l + r >> 1;
if(p <= mid) {
insert(p, ls, l, mid);
mul(t[rs], M);
++ tag[rs];
}
else insert(p, rs, mid + 1, r);
pushup(x);
}
inline void erase(int p, int x = 1, int l = 1, int r = tot) {
if(l == r) return val[x] = 0, void();
pushdown(x);
int mid = l + r >> 1;
if(p <= mid) {
erase(p, ls, l, mid);
mul(t[rs], invM);
-- tag[rs];
}
else erase(p, rs, mid + 1, r);
pushup(x);
}
int cnt[N], ans[N];
inline void add(int x) {
if(++ cnt[x] == 1) insert(x);
}
inline void del(int x) {
if(-- cnt[x] == 0) erase(x);
}
#define c(x) ((x) / B)
struct qry {
int l, r, id;
bool operator < (const qry &x) {
if(c(l) != c(x.l)) return c(l) < c(x.l);
if(c(l) & 1) return c(r) < c(x.r);
return c(r) > c(x.r);
}
} q[N];
void init_Fib() {
rep(i, 1, n) {
memcpy(Fib[i], Fib[i - 1], 16);
memcpy(invFib[i], invFib[i - 1], 16);
mul(Fib[i], M);
mul(invFib[i], invM);
}
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
cin >> n >> P;
invM[3] = P - 1;
init_Fib();
rep(i, 1, n) {
cin >> a[i];
b[i] = a[i];
}
sort(b + 1, b + n + 1);
tot = unique(b + 1, b + n + 1) - b - 1;
rep(i, 1, n) {
a[i] = lower_bound(b + 1, b + tot + 1, a[i]) - b;
}
rep(i, 1, tot) {
b[i] = (b[i] % P + P) % P;
}
cin >> m;
rep(i, 1, m) {
cin >> q[i].l >> q[i].r;
q[i].id = i;
}
sort(q + 1, q + m + 1);
build();
int l = 1, r = 0;
rep(i, 1, m) {
auto[L, R, id] = q[i];
while(l < L) del(a[l ++]);
while(l > L) add(a[-- l]);
while(r < R) add(a[++ r]);
while(r > R) del(a[r --]);
ans[id] = t[1][2] % P;
}
rep(i, 1, m) cout << ans[i] << '\n';
return 0;
}
CF633H (线段树维护矩乘 + 莫队)的更多相关文章
- 洛谷 P7879 -「SWTR-07」How to AK NOI?(后缀自动机+线段树维护矩乘)
洛谷题面传送门 orz 一发出题人(话说我 AC 这道题的时候,出题人好像就坐在我的右侧呢/cy/cy) 考虑一个很 naive 的 DP,\(dp_i\) 表示 \([l,i]\) 之间的字符串是否 ...
- bzoj 4184: shallot (线段树维护线性基)
题面 \(solution:\) 这一题绝对算的上是一道经典的例题,它向我们诠释了一种新的线段树维护方式(神犇可以跳过了).像这一类需要加入又需要维护删除的问题,我们曾经是遇到过的像莫对,线段树... ...
- BZOJ1878 [SDOI2009]HH的项链 树状数组 或 莫队
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1878 题意概括 给出一个长度为n的序列,用m次询问,问区间Li~Ri中有多少种不同的数. 0< ...
- 【BZOJ】4129: Haruna’s Breakfast 树分块+带修改莫队算法
[题意]给定n个节点的树,每个节点有一个数字ai,m次操作:修改一个节点的数字,或询问一条树链的数字集合的mex值.n,m<=5*10^4,0<=ai<=10^9. [算法]树分块+ ...
- 线段树维护矩阵【CF718C】 Sasha and Array
Description 有一个长为\(n\)的数列\(a_{1},a_{2}...a_{n}\),你需要对这个数列维护如下两种操作: \(1\space l \space r\space x\) 表示 ...
- 2016shenyang-1002-HDU5893-List wants to travel-树链剖分+线段树维护不同区间段个数
肯定先无脑树链剖分,然后线段树维护一段区间不同个数,再维护一个左右端点的费用. 线段树更新,pushDown,pushUp的时候要注意考虑链接位置的费用是否相同 还有就是树链剖分操作的时候,维护上一个 ...
- Codeforces GYM 100114 D. Selection 线段树维护DP
D. Selection Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100114 Descriptio ...
- [BZOJ 3995] [SDOI2015] 道路修建 【线段树维护连通性】
题目链接:BZOJ - 3995 题目分析 这道题..是我悲伤的回忆.. 线段树维护连通性,与 BZOJ-1018 类似,然而我省选之前并没有做过 1018,即使它在 ProblemSet 的第一页 ...
- [BZOJ 1018] [SHOI2008] 堵塞的交通traffic 【线段树维护联通性】
题目链接:BZOJ - 1018 题目分析 这道题就说明了刷题少,比赛就容易跪..SDOI Round1 Day2 T3 就是与这道题类似的..然而我并没有做过这道题.. 这道题是线段树维护联通性的经 ...
- HDU3564 --- Another LIS (线段树维护最值问题)
Another LIS Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total ...
随机推荐
- BorderDet:通过边界特征大幅提升检测准确率,即插即用且速度不慢 | ECCV 2020 Oral
边界对于定位问题十分重要,BorderDet的核心思想BorderAlign巧妙又有效,将边界特征融入到目标定位预测中,而且能够简单地融入到各种目标检测算法中带来较大的性能提升下.在开源实现中,对Bo ...
- #扫描线,线段树#nssl 1459 空间复杂度
分析 由于\(k\leq 10\)所以考虑用总方案减去经过两个差的绝对值\(\leq k\)的点的路径数 分类讨论一下发现要处理祖先关系和其它关系两种情况,考虑怎么去重,可以将这些答案看作一个个矩形, ...
- 陈海波:OpenHarmony技术领先,产学研深度协同,生态蓬勃发展
11月4日,以"技术筑生态,智联赢未来"为主题的第二届OpenHarmony技术大会在北京隆重举办.本次大会由OpenAtom OpenHarmony(简称"Open ...
- OpenHarmony父子组件单项同步使用:@Prop装饰器
@Prop装饰的变量可以和父组件建立单向的同步关系.@Prop装饰的变量是可变的,但是变化不会同步回其父组件. 说明: 从API version 9开始,该装饰器支持在ArkTS卡片中使用. 概述 ...
- 【Insights直播】华为帐号服务,打造全场景安全帐号体系
在App运营过程中,如何保持用户增长和提升用户体验始终是开发者关注的问题,而作为用户使用体验感知的第一环节--帐号注册登录环节是不可忽视,且有很大提升空间的.如何提升帐号的注册登录体验?如何保证用户在 ...
- openGauss每日一练(全文检索)
openGauss 每日一练(全文检索) 本文出处:https://www.modb.pro/db/224179 学习目标 学习 openGauss 全文检索 openGauss 提供了两种数据类型用 ...
- HarmonyOS开发案例分享:万能卡片也能用来玩游戏
一.前言 作为一名开发爱好者,从大了讲,我学习并进行HarmonyOS相关开发是为了能为鸿蒙生态建设尽一份绵薄之力,从小了讲,就是为了自己的兴趣.而万能卡片是一个让我非常感兴趣的东西. 很多时候我跟别 ...
- Java+HTML预习笔记_20140610
1.HTML <img> 标签 HTML <img> 标签 实例 在下面的例子中,我们在页面中插入一幅 W3School 的工程师在上海鲜花港拍摄的郁金香照片: <img ...
- CentOS下安装OpenSSH 5.8的三种方法【未测试】
CentOS下安装OpenSSH 5.8的三种方法 Category : 工作学习 / Tags : centos, linux, openssh / Date : 2011.05.19 / 5,29 ...
- linux 性能自我学习 ———— cpu 高怎么办 [三]
前言 linux 性能分析自我学习. 正文 一般我们说cpu,一般是什么高呢? 一般是指cpu 使用率高. 那么什么是cpu 使用率呢? cpu 使用率 = 1- 空闲时间/总cpu 时间 平均cpu ...