洛谷P3328(bzoj 4085)毒瘤线段树
题面及大致思路:https://www.cnblogs.com/Yangrui-Blog/p/9623294.html, https://www.cnblogs.com/New-Godess/p/4567282.html
每个点维护2个矩阵,一共15个变量。矩阵a: [a(i - 1), a(i), a(i + 1); b(i - 1), b(i), b(i + 1)], 矩阵b就是a(i - 1), a(i), a(i + 1)与b(i - 1), b(i), b(i + 1)的两两乘积,矩阵转移的过程很显然,就不细说了。这个题的思维难度不高,就是两点很烦人:1 卡常 2 维护变量很麻烦。
代码:
#include <bits/stdc++.h>
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
using namespace std;
const int mod = 1000000007;
const int maxn = 300010;
int c[maxn][4];
int a, b, inv;
int qpow(int x, int y) {
int ans = 1;
for(; y; y >>= 1) {
if(y & 1) ans = 1ll * ans * x % mod;
x = 1ll * x * x % mod;
}
return ans;
}
struct Matrix {
int a[3][3], n, m;
void init(int x) {
memset(a, 0, sizeof(a));
n = m = x;
for (int i = 0; i < n; i++) a[i][i] = 1;
}
Matrix operator * (const Matrix &rhs) const {
Matrix ret; memset(ret.a, 0, sizeof(ret.a));
ret.n = n, ret.m = rhs.m;
for (int i = 0; i < n; i++)
for (int k = 0; k < m; k++)
for (int j = 0; j < 2; j++)
ret.a[i][j] = (ret.a[i][j] + 1ll * a[i][k] * rhs.a[k][j] % mod) % mod;
ret.a[2][2] = 1;
return ret;
}
};
Matrix A, B, p[35], E;
Matrix qpow(int k) {
Matrix ans = E;
for (int i = 1; k; i++, k >>= 1) {
if(k & 1) ans = ans * p[i];
}
return ans;
}
void get_Matrix(int pos) {
Matrix tmp = A * qpow(c[pos][0] - 2);
c[pos][1] = tmp.a[0][1], c[pos][2] = tmp.a[0][0];
}
void init_p() {
A.n = 1, A.m = 3;
A.a[0][0] = 2, A.a[0][1] = 1, A.a[0][2] = 1;
B.n = B.m = 3;
B.a[0][0] = 1; B.a[1][0] = a, B.a[2][0] = b;
B.a[0][1] = 1; B.a[2][2] = 1;
for (int i = 1; i <= 32; i++) {
p[i] = B;
B = B * B;
}
}
struct SegementTree {
int sum[2][3], val[3][3], l, r, lz[2];
};
SegementTree tr[maxn * 4];
inline void pushup(int now) {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
tr[now].val[i][j] = (tr[ls(now)].val[i][j] + tr[rs(now)].val[i][j]) % mod;
for (int i = 0; i < 2; i++)
for (int j = 0; j < 3; j++)
tr[now].sum[i][j] = (tr[ls(now)].sum[i][j] + tr[rs(now)].sum[i][j]) % mod;
}
inline void add1(int now, int flag) {
int l = tr[now].l, r = tr[now].r;
for (int i = 0; i < 2; i++)
tr[now].sum[flag][i] = tr[now].sum[flag][i + 1];
tr[now].sum[flag][2] = (tr[now].sum[flag][1] + 1ll * tr[now].sum[flag][0] * a + 1ll * b * (r - l + 1)) % mod;
if(flag == 0) {
for (int i = 0; i < 2; i++)
for (int j = 0 ; j < 3; j++)
tr[now].val[i][j] = tr[now].val[i + 1][j];
for (int j = 0; j < 3; j++)
tr[now].val[2][j] = (tr[now].val[1][j] + 1ll * tr[now].val[0][j] * a + 1ll * b * tr[now].sum[1][j]) % mod;
} else {
for (int i = 0; i < 3; i++)
for (int j = 0; j < 2; j++)
tr[now].val[i][j] = tr[now].val[i][j + 1];
for (int i = 0; i < 3; i++)
tr[now].val[i][2] = (tr[now].val[i][1] + 1ll * tr[now].val[i][0] * a + 1ll * b * tr[now].sum[0][i]) % mod;
}
}
inline void dec1(int now, int flag) {
int l = tr[now].l, r = tr[now].r;
if(a == 0) {
for (int i = 1; i >= 0; i--) tr[now].sum[flag][i + 1] = tr[now].sum[flag][i];
tr[now].sum[flag][0] = (tr[now].sum[flag][1] - 1ll * b * (r - l + 1) % mod + mod) % mod;
if(flag == 0) {
for (int i = 1; i >= 0; i--)
for (int j = 0; j < 3; j++)
tr[now].val[i + 1][j] = tr[now].val[i][j];
for (int i = 0; i < 3; i++)
tr[now].val[0][i] = (tr[now].val[1][i] - 1ll * b * tr[now].sum[1][i] % mod + mod) % mod;
} else {
for (int i = 0; i < 3; i++)
for (int j = 1; j >= 0; j--)
tr[now].val[i][j + 1] = tr[now].val[i][j];
for (int i = 0; i < 3; i++)
tr[now].val[i][0] = (tr[now].val[i][1] - 1ll * b * tr[now].sum[0][i] % mod + mod) % mod;
}
return;
}
for (int i = 1; i >= 0; i--)
tr[now].sum[flag][i + 1] = tr[now].sum[flag][i];
tr[now].sum[flag][0] = ((tr[now].sum[flag][2] - tr[now].sum[flag][1] - 1ll * b * (r - l + 1) % mod) * inv % mod + mod) % mod;
if(flag == 0) {
for (int i = 1; i >= 0; i--)
for (int j = 0; j < 3; j++)
tr[now].val[i + 1][j] = tr[now].val[i][j];
for (int i = 0; i < 3; i++)
tr[now].val[0][i] = ((tr[now].val[2][i] - tr[now].val[1][i] - 1ll * b * tr[now].sum[1][i] % mod) % mod * inv % mod + mod) % mod;
} else {
for (int i = 0; i < 3; i++)
for (int j = 1; j >= 0; j--)
tr[now].val[i][j + 1] = tr[now].val[i][j];
for (int i = 0; i < 3; i++)
tr[now].val[i][0] = ((tr[now].val[i][2] - tr[now].val[i][1] - 1ll * b * tr[now].sum[0][i] % mod) % mod * inv % mod + mod) % mod;
}
}
inline void pushdown(int now, int flag, int y) {
if(y > 0) for (int i = 1; i <= y; i++) add1(now, flag);
else for (int i = -1; i >= y; i--) dec1(now, flag);
}
inline void Pushdown(int now) {
for (int flag = 0; flag < 2; flag++) {
pushdown(ls(now), flag, tr[now].lz[flag]);
pushdown(rs(now), flag, tr[now].lz[flag]);
tr[ls(now)].lz[flag] += tr[now].lz[flag];
tr[rs(now)].lz[flag] += tr[now].lz[flag];
tr[now].lz[flag] = 0;
}
}
inline void build(int now, int l, int r) {
tr[now].l = l, tr[now].r = r;
if(l == r) {
for (int i = 0; i < 3; i++) {
tr[now].sum[0][i] = c[l - 1][i + 1];
tr[now].sum[1][i] = c[l + 1][i + 1];
}
for (int i = 0; i < 3; i++)
for (int j = 0;j < 3; j++)
tr[now].val[i][j] = 1ll * tr[now].sum[0][i] * tr[now].sum[1][j] % mod;
return;
}
int mid = (l + r) >> 1;
build(ls(now), l, mid);
build(rs(now), mid + 1, r);
pushup(now);
}
inline void update(int now, int ql, int qr, int flag,int val) {
int l = tr[now].l, r = tr[now].r;
if(l > qr || r < ql) return;
if(l >= ql && r <= qr) {
tr[now].lz[flag] += val;
pushdown(now, flag, val);
return;
}
Pushdown(now);
int mid = (l + r) >> 1;
if(ql <= mid) update(ls(now), ql, qr, flag, val);
if(qr > mid) update(rs(now), ql, qr, flag, val);
pushup(now);
}
inline int query(int now, int ql, int qr) {
int l = tr[now].l, r = tr[now].r;
if(l > qr || r < ql) return 0;
if(l >= ql && r <= qr) return tr[now].val[2][0];
Pushdown(now);
int mid = (l + r) >> 1;
int ans = 0;
if(ql <= mid) ans = (ans + query(ls(now), ql, qr)) % mod;
if(qr > mid) ans = (ans + query(rs(now), ql, qr)) % mod;
return ans;
}
int main() {
int n, m;
scanf("%d%d%d%d", &n, &m, &a, &b);
inv = qpow(a, mod - 2);
E.init(3);
init_p();
for (int i = 1; i <= n; i++) {
scanf("%d", &c[i][0]);
get_Matrix(i);
c[i][3] = (c[i][2] + 1ll * a * c[i][1] % mod + b) % mod;
}
char op[10];
build(1, 2, n - 1);
while(m--) {
scanf("%s", op + 1);
int x, y;
scanf("%d%d", &x, &y);
if(op[1] == 'p') {
update(1, x + 1, y + 1, 0, 1);
update(1, x - 1, y - 1, 1, 1);
} else if (op[1] == 'm') {
update(1, x + 1, y + 1, 0, -1);
update(1, x - 1, y - 1, 1, -1);
} else {
printf("%d\n", query(1, x + 1, y - 1));
}
}
}
洛谷P3328(bzoj 4085)毒瘤线段树的更多相关文章
- 洛谷 P3373 【模板】线段树 2
洛谷 P3373 [模板]线段树 2 洛谷传送门 题目描述 如题,已知一个数列,你需要进行下面三种操作: 将某区间每一个数乘上 xx 将某区间每一个数加上 xx 求出某区间每一个数的和 输入格式 第一 ...
- 洛谷P4891 序列(势能线段树)
洛谷题目传送门 闲话 考场上一眼看出这是个毒瘤线段树准备杠题,发现实在太难调了,被各路神犇虐哭qwq 考后看到各种优雅的暴力AC......宝宝心里苦qwq 思路分析 题面里面是一堆乱七八糟的限制和性 ...
- Bzoj5294/洛谷P4428 [Bjoi2018]二进制(线段树)
题面 Bzoj 洛谷 题解 考虑一个什么样的区间满足重组之后可以变成\(3\)的倍数.不妨设\(tot\)为一个区间内\(1\)的个数.如果\(tot\)是个偶数,则这个区间一定是\(3\)的倍数,接 ...
- 洛谷P3372 【模板】线段树 1
P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交 讨论 题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷 ...
- 洛谷 P2574 XOR的艺术(线段树 区间异或 区间求和)
To 洛谷.2574 XOR的艺术 题目描述 AKN觉得第一题太水了,不屑于写第一题,所以他又玩起了新的游戏.在游戏中,他发现,这个游戏的伤害计算有一个规律,规律如下 1. 拥有一个伤害串为长度为n的 ...
- 洛谷P4344 脑洞治疗仪 [SHOI2015] 线段树+二分答案/分块
!!!一道巨恶心的数据结构题,做完当场爆炸:) 首先,如果你用位运算的时候不小心<<打成>>了,你就可以像我一样陷入疯狂的死循环改半个小时 然后,如果你改出来之后忘记把陷入死循 ...
- 【题解】洛谷P1198 [JSOI2008] 最大数(线段树)
洛谷P1198:https://www.luogu.org/problemnew/show/P1198 思路 一道水水的线段树 20分钟A掉 这道题只涉及到单点修改和区间查询 所以这道题甚至不用Laz ...
- bzoj3064/洛谷P4314 CPU监控【线段树】
好,长草博客被催更了[?] 我感觉这题完全可以当作线段树3 线段树2考加法和乘法标记的下放顺序,这道题更丧心病狂[?] 很多人可能跟我一样,刚看到这道题秒出思路:打一个当前最大值一个历史最大值不就完事 ...
- [BZOJ5286][洛谷P4425][HNOI2018]转盘(线段树)
5286: [Hnoi2018]转盘 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 15 Solved: 11[Submit][Status][Di ...
- 洛谷P3373 【模板】线段树 2
P3373 [模板]线段树 2 47通过 186提交 题目提供者HansBug 标签 难度提高+/省选- 提交 讨论 题解 最新讨论 为啥WA(TAT) 题目描述 如题,已知一个数列,你需要进行 ...
随机推荐
- 如何在windows上部署war包到tomcat服务器
一. 什么是war包 WAR(Web Archive file)网络应用程序文件,是与平台无关的文件格式,它允许将很多文件组合成一个压缩文件.war专用在web方面,一个war包可以理解为一个web项 ...
- nginx基本参数详解
运行用户 user nobody; 启动进程,通常设置成和cpu的数量相等 worker_processes 1; 全局错误日志及PID文件 error_log logs/error.log; err ...
- jar包作用
hibernate中jar包的作用 (1)hibernate3.jar:Hibernate的核心库,没有什么可说的,必须使用的jar包 (2)cglib-asm.jar:CGLIB库,Hibernat ...
- 常用T-CODE ,快捷键
RSA1 --主界面. RSA8 --后台处理数据源和层次结构,很少使用 RSRT --QUERY 测试 .输入技术名称查询即可 RSRV--分析修复BW对象 RSMO --信息包监测. 检查处理链 ...
- 实现多层抽屉菜单,点击其中一项会动画打开该抽屉--第三方开源--MultiCardMenu
下载地址:https://github.com/wujingchao/MultiCardMenu <net.wujingchao.android.view.MultiCardMenu xmlns ...
- L107
It is advisable to take an open- minded approach to new idea. 对新思想采取不存先入之见的态度是明智的.That said, the com ...
- BRICH
一.简介 Brich是典型的基于层次的聚类算法.最大的特点就是适合数据量特别大的数据集,处理速度很快,因为该算法扫描一遍数据集. 该算法是利用了一个树状结构来快速聚类,该结构类似平衡B+树.每一个叶子 ...
- linux shell 学习笔记--变量声明与赋值,循环
Bash 变量是不分类型的 ------------------------ 不像其他程序语言一样,Bash 并不对变量区分"类型".本质上,Bash 变量都是字符串. 但是依赖于 ...
- 关于 freetds pymssql 的安装部署
关于 freetds pymssql 的安装部署一.安装: (freetds-0.91 pymssql 2.0.1) 如果要在linux机器 连mysqlsever 1.需要安装freetds./co ...
- [BZOJ4573][ZJOI2016]大♂森林
bzoj luogu uoj sol \(orz\ \ HJT\ \ dalao\)教会我做这道题. 考虑每两个相邻位置的树的差异. 对于一个1操作(更换生长节点),假设区间是\([l,r]\),那么 ...