P6864 RC-03 记忆
设当前括号串 \(S\) 中:
- 合法括号非空 子串 数量为 \(\mathrm{ans}\)。
- 合法括号非空 后缀子串 数量为 \(\mathrm{cnt}\)。
例: \(S = \mathtt{()()}\),则 \(\mathrm{ans} = 3\),\(\mathrm{cnt} = 2\)。
设 \(S\) 进行一步操作一后,变为括号串 \(S_1 = \overline{S\mathtt{()}}\),相应参数变为 \(\mathrm{ans}_1\) 和 \(\mathrm{cnt}_1\)。
现试图找到 \(\mathrm{ans_1}\) 和 \(\mathrm{ans}\)、\(\mathrm{cnt_1}\) 和 \(\mathrm{cnt}\) 的关系。
不难发现 \(\mathrm{cnt_1 = cnt + 1}\),\(\mathrm{ans_1 = ans + cnt + 1}\)。
再设 \(S\) 进行一步操作二后,变为括号串 \(S_2 = \overline{\mathtt ( S\mathtt)}\),相应参数 \(\mathrm{ans_2}\) 和 \(\mathrm{cnt_2}\)。
我们试图证明,新增的合法括号非空子串只有 \(\boldsymbol{S_2}\) 本身一个。
反证法,我们考虑有没有可能,新加的这对括号中的左括号,和 \(S\) 的一段前缀组成一段合法括号子串?
很明显,这要求 \(S\) 的这段前缀中,右括号比左括号多一个。
但在操作的变换中,字符串始终是合法括号串。因此,\(S\) 不可能存在一段右括号比左括号多的前缀。
那有无可能,新加的这对括号中的右括号,和 \(S\) 的一段后缀组成一段合法括号子串?
这要求 \(S\) 的这段后缀里,左括号比右括号多一个。
可以发现,这就意味着 \(S\) 除去这段后缀的剩余那部分前缀,右括号比左括号多一个(因为整个括号串左右括号数相等),所以同样不可能。
那么新增的合法括号子串只有 \(S_2\) 本身一个咯。
所以 \(\mathrm{cnt_2} = 1\),\(\mathrm{ans_2} = \mathrm{ans} + 1\)。
现在考虑撤销操作。发现撤销操作对 \(\mathrm{cnt}\) 和 \(\mathrm{ans}\) 的变化并不平凡。
然后这里有一个比较不朴素的想法……那就是用矩阵刻画上面两种操作的变换。
刻画还是较为容易的:
那么答案可以看做初始矩阵 \(\begin{bmatrix}1 & 1 & 1\end{bmatrix}\) 经过一系列矩阵乘法得到的结果。
那撤销是什么?题目的撤销还可以撤销一个撤销操作,看起来很高级,但它的影响最后无非都是:
- 将某个非撤销操作(即操作一或操作二)从进行改为不进行。
- 将某个非撤销操作(即操作一或操作二)从不进行改为进行。
不进行操作也是可以刻画出矩阵的,即单位矩阵 \(\begin{bmatrix}1 & 0 & 0 \\0 & 1 & 0 \\ 0 & 0 & 1\end{bmatrix}\)。
所以任何一个撤销操作都是将一个非撤销操作对应的矩阵单点修改,要么是从操作矩阵修改成单位矩阵,要么是从单位矩阵修改成操作矩阵。
因此现在变成一个对矩阵单点修改,求矩阵全局乘法的问题。因为矩阵乘法有结合律,可以用线段树维护。
因为矩阵乘法没法差分,所以不能用单 \(\log\) 的树状数组。
时间复杂度 \(\Theta(K^3 n \log n)\),其中 \(K = 3\)。
/*
 * @Author: crab-in-the-northeast 
 * @Date: 2023-05-15 16:06:19 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2023-05-15 19:15:26
 */
#include <bits/stdc++.h>
#define int long long
inline int read() {
    int x = 0;
    bool f = true;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar())
        if (ch == '-')
            f = false;
    for (; isdigit(ch); ch = getchar())
        x = (x << 1) + (x << 3) + ch - '0';
    return f ? x : (~(x - 1));
}
inline int ls(int p) {
    return p << 1;
}
inline int rs(int p) {
    return p << 1 | 1;
}
struct phalanx {
    int a[4][4];
    phalanx () {
        for (int i = 1; i <= 3; ++i)
            for (int j = 1; j <= 3; ++j)
                a[i][j] = 0;
    }
    phalanx (std :: vector <int> v) {
        for (int i = 1; i <= 3; ++i)
            for (int j = 1; j <= 3; ++j)
                a[i][j] = v[(i - 1) * 3 + j - 1];
    }
    const phalanx operator * (const phalanx b) const {
        phalanx ans;
        for (int i = 1; i <= 3; ++i)
            for (int j = 1; j <= 3; ++j)
                for (int k = 1; k <= 3; ++k)
                    ans.a[i][j] += a[i][k] * b.a[k][j];
        return ans;
    }
};
const phalanx UNIT({1, 0, 0, 0, 1, 0, 0, 0, 1}), 
                OP1({1, 0, 0, 1, 1, 0, 1, 1, 1}),
                OP2({1, 0, 0, 0, 0, 0, 1, 1, 1});
const int N = (int)2e5 + 5;
struct node {
    int l, r;
    phalanx ans;
} t[N << 2];
inline node con(node lef, node rgt) {
    return (node){
        l: lef.l,
        r: rgt.r,
        ans: lef.ans * rgt.ans
    };
}
inline void up(int p) {
    t[p] = con(t[ls(p)], t[rs(p)]);
}
void build(int p, int l, int r) {
    if (l == r) {
        t[p].l = t[p].r = l;
        t[p].ans = UNIT;
        return ;
    }
    int mid = (l + r) >> 1;
    build(ls(p), l, mid);
    build(rs(p), mid + 1, r);
    up(p);
}
void modify(int p, int x, int op) {
    int l = t[p].l, r = t[p].r;
    if (l == r) {
        if (op == 1)
            t[p].ans = OP1;
        else if (op == 2)
            t[p].ans = OP2;
        else
            t[p].ans = UNIT;
        return ;
    }
    int mid = (l + r) >> 1;
    if (x <= mid)
        modify(ls(p), x, op);
    else
        modify(rs(p), x, op);
    up(p);
}
int ops[N];
int pos[N];
signed main() {
    int n = read();
    build(1, 1, n);
    for (int i = 1; i <= n; ++i) {
        int op = ops[i] = read();
        pos[i] = i;
        if (op <= 2)
            modify(1, i, op);
        else {
            int p = read();
            p = pos[i] = pos[p];
            ops[p] = -ops[p];
            modify(1, p, ops[p]);
        }
        phalanx ans = t[1].ans;
        printf("%lld\n", ans.a[1][1] + ans.a[2][1] + ans.a[3][1]);
    }
    return 0;
}

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号