Addition Robot

直接做是难的,发现这个东西似乎可以矩阵优化。

可以发现 [a+bb]=[ab]×[1011]\begin{bmatrix} a+b&b \end{bmatrix} = \begin{bmatrix} a & b \end{bmatrix} \times \begin{bmatrix} 1 & 0 \\ 1 & 1\end{bmatrix}[aa+b]=[ab]×[1101]\begin{bmatrix} a & a + b \end{bmatrix} = \begin{bmatrix} a&b \end{bmatrix} \times \begin{bmatrix} 1 & 1\\ 0 & 1\end{bmatrix}

对于 SiS_iA\texttt{A},那么令 pi=[1011]p_i = \begin{bmatrix} 1 & 0 \\ 1 & 1\end{bmatrix},否则 pi=[1101]p_i = \begin{bmatrix} 1 & 1\\ 0 & 1\end{bmatrix}

那么对于询问 l,r,a,bl, r, a, b,则最终矩阵应该为 [ab]×i=lrpi\begin{bmatrix} a & b \end{bmatrix} \times \prod \limits_{i=l}^r p_i

容易发现可以线段树维护矩阵乘法。

对于区间反转,只需要维护区间反转后的乘积和反转前的乘积,反转时交换两个结果即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;

const int N = 1e5 + 5;
const long long MOD = 1e9 + 7;
string s;
int n, m;

struct Matrix
{
	long long a[3][3];
	Matrix(long long ax, long long b, long long c, long long d)
	{
		a[1][1] = ax, a[1][2] = b, a[2][1] = c, a[2][2] = d;
	}
	Matrix()
	{
		a[0][0] = a[0][1] = a[0][2] = a[1][0] = a[1][1] = a[1][2] = a[2][0] = a[2][1] = a[2][2] = 0LL;
	}
	void Clear()
	{
		a[1][1] = -1LL;
	}
	friend Matrix operator*(const Matrix& a, const Matrix& b)
	{
		if (a.a[1][1] == -1LL) return b;
		if (b.a[1][1] == -1LL) return a;
		Matrix c;
		for (int i = 1; i <= 2; i++)
		{
			for (int j = 1; j <= 2; j++)
			{
				for (int k = 1; k <= 2; k++)
				{
					c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j]) % MOD;
				}
			}
		}
		return c;
	}
};

class SegmentTree
{
public:
	struct Node
	{
		int l, r;
		Matrix ans1, ans2;
		bool revtag;
	}tr[N << 2];
	void pushup(int u)
	{
		tr[u].ans1 = tr[u << 1].ans1 * tr[u << 1 | 1].ans1;
		tr[u].ans2 = tr[u << 1].ans2 * tr[u << 1 | 1].ans2;
	}
	void pushdown(int u)
	{
		if (tr[u].revtag)
		{
			tr[u].revtag = 0;
			swap(tr[u << 1].ans1, tr[u << 1].ans2);
			tr[u << 1].revtag ^= 1;
			swap(tr[u << 1 | 1].ans1, tr[u << 1 | 1].ans2);
			tr[u << 1 | 1].revtag ^= 1;
		}
	}
	void build(int u, int l, int r)
	{
		if (l == r)
		{
			tr[u] = { l, r };
			char c = s[l - 1];
			if (c == 'A')
			{
				tr[u].ans1 = Matrix(1LL, 0LL, 1LL, 1LL);
				tr[u].ans2 = Matrix(1LL, 1LL, 0LL, 1LL);
			}
			else
			{
				tr[u].ans2 = Matrix(1LL, 0LL, 1LL, 1LL);
				tr[u].ans1 = Matrix(1LL, 1LL, 0LL, 1LL);
			}
			return;
		}
		tr[u] = { l, r };
		int mid = l + r >> 1;
		build(u << 1, l, mid);
		build(u << 1 | 1, mid + 1, r);
		pushup(u);
	}
	void update(int u, int l, int r)
	{
		if (tr[u].l >= l and tr[u].r <= r)
		{
			tr[u].revtag ^= 1;
			swap(tr[u].ans1, tr[u].ans2);
			return;
		}
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1;
		if (l <= mid) update(u << 1, l, r);
		if (r > mid) update(u << 1 | 1, l, r);
		pushup(u);
	}
	Matrix query(int u, int l, int r)
	{
		if (tr[u].l >= l and tr[u].r <= r)
		{
			return tr[u].ans1;
		}
		pushdown(u);
		int mid = tr[u].l + tr[u].r >> 1;
		Matrix res;
		res.Clear();
		if (l <= mid) res = query(u << 1, l, r);
		if (r > mid) res = res * query(u << 1 | 1, l, r);
		return res;
	}
}tr;

int main()
{
	ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> m >> s;
	tr.build(1, 1, n);
	while (m--)
	{
		int opt;
		cin >> opt;
		if (opt == 1)
		{
			int l, r;
			cin >> l >> r;
			tr.update(1, l, r);
		}
		else
		{
			int l, r;
			long long a, b;
			cin >> l >> r >> a >> b;
			Matrix res(a, b, 0LL, 0LL);
			res = res * tr.query(1, l, r);
			Matrix p = tr.query(1, l, r);
			printf("%lld %lld\n", res.a[1][1], res.a[1][2]);
		}
	}
	return 0;
}
posted @   HappyBobb  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示