P6864 [RC-03] 记忆 题解

题目传送门

2025 最后一天来写题解祭

思路

一道好题。我们考虑用线段树维护矩阵乘法来快速得出一段操作区间后的答案。设 \(\begin{bmatrix} x & y & 1\end{bmatrix}\) 分别代表当前区间的答案 \(x\),当前区间能被分割成最多的括号匹配子串的个数 \(y\),和常数 \(1\)

操作 1

这种操作是将 \(S\) 变为新串 $S' = $ S()。我们会发现对答案有贡献即需要保证当前子串是 \(S'\) 的后缀,且为括号匹配序列。则贡献就为 \(y + 1\)(还可以只选自己,即 ())。那新答案 \(x'\)\(x + y + 1\),且 \(y'\) 变为 \(y + 1\)。写为矩阵即为:

\[\begin{bmatrix} 1 & 0 & 0 \\ 1 & 1 & 0 \\ 1 & 1 & 1 \\ \end{bmatrix} \]

操作 2

这种操作将 \(S\) 变为新串 $S' = $ (S)。我们发现对答案只有一个,即 (S)。所以,\(x' = x + 1\)\(y' = 1\)。写为矩阵即为

\[\begin{bmatrix} 1 & 0 & 0 \\ 0 & 0 & 0 \\ 1 & 1 & 1 \\ \end{bmatrix} \]

操作 3

撤销操作。分类讨论一下,如果撤销的效果是将第 \(x\) 个操作删去,则单点修改,把点 \(x\) 所维护的矩阵设为单位矩阵;否则,把点 \(x\) 所维护的矩阵设为原本的矩阵。

答案矩阵 \(ans = \begin{bmatrix} 1 & 1 & 1 \end{bmatrix} \times ans\) 即可。注意顺序!

最后时间复杂度 \(\mathcal{O}(q \log n)\)。可以通过此题。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;

const int N = 2e5 + 5;

int n;
int op[N], tag[N], num[N];

struct Matrix
{
	int m, n;
	int val[5][5];
	void clear()
	{
		memset(val, 0, sizeof(val));
	}
	Matrix operator*(const Matrix &rhs)
	{
		Matrix res;
		res.m = m, res.n = rhs.n;
		res.clear();
		for (int k = 1; k <= n; k++)
			for (int i = 1; i <= m; i++)
				for (int j = 1; j <= rhs.n; j++)
					res.val[i][j] += val[i][k] * rhs.val[k][j];
		return res;
	}
} A, B, C, D;

struct seg_tree
{
	Matrix tr[4 * N];
	void push_up(int p)
	{
		tr[p] = tr[p * 2] * tr[p * 2 + 1];
	}
	void build(int p, int l, int r)
	{
		tr[p].clear();
		if (l == r)
		{
			tr[p] = C;
			return;
		}
		int mid = (l + r) >> 1;
		build(p * 2, l, mid);
		build(p * 2 + 1, mid + 1, r);
		push_up(p);
	}
	void modify(int p, int l, int r, int k, Matrix x)
	{
		if (l == r)
		{
			tr[p] = x;
			return;
		}
		int mid = (l + r) >> 1;
		if (k <= mid) modify(p * 2, l, mid, k, x);
		else modify(p * 2 + 1, mid + 1, r, k, x);
		push_up(p);
	}
} ST;

void init()
{
	A.clear(), B.clear(), C.clear(), D.clear();
	A.val[1][1] = A.val[2][1] = A.val[3][1] = A.val[2][2] = A.val[3][2] = A.val[3][3] = 1;
	B.val[1][1] = B.val[3][1] = B.val[3][2] = B.val[3][3] = 1;
	C.val[1][1] = C.val[2][2] = C.val[3][3] = 1;
	D.val[1][1] = D.val[1][2] = D.val[1][3] = 1;
	A.m = A.n = B.m = B.n = C.m = C.n = D.n = 3, D.m = 1;
}

signed main()
{
	init();
	scanf("%lld", &n);
	ST.build(1, 1, n);
	for (int i = 1, x; i <= n; i++)
	{
		scanf("%lld", &op[i]);
		if (op[i] == 1)
		{
			tag[i] = 1, num[i] = i;
			ST.modify(1, 1, n, i, A);
		}
		else if (op[i] == 2)
		{
			tag[i] = 2, num[i] = i;
			ST.modify(1, 1, n, i, B);
		}
		else
		{
			scanf("%lld", &x);
			op[i] = op[x], tag[i] = -tag[x], num[i] = num[x];
			if (tag[i] < 0) ST.modify(1, 1, n, num[i], C);
			else
			{
				if (op[i] == 1) ST.modify(1, 1, n, num[i], A);
				else ST.modify(1, 1, n, num[i], B);
			}
		}
		Matrix ans;
		ans = D * ST.tr[1];
		printf("%lld\n", ans.val[1][1]);
	}
	return 0;
}
posted @ 2026-01-01 15:07  lucasincyber  阅读(2)  评论(0)    收藏  举报