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;
}

浙公网安备 33010602011771号