P6864 RC-03 记忆

P6864 RC-03 记忆

设当前括号串 SS 中:

  • 合法括号非空 子串 数量为 ans\mathrm{ans}
  • 合法括号非空 后缀子串 数量为 cnt\mathrm{cnt}

例: S=()()S = \mathtt{()()},则 ans=3\mathrm{ans} = 3cnt=2\mathrm{cnt} = 2

SS 进行一步操作一后,变为括号串 S1=S()S_1 = \overline{S\mathtt{()}},相应参数变为 ans1\mathrm{ans}_1cnt1\mathrm{cnt}_1

现试图找到 ans1\mathrm{ans_1}ans\mathrm{ans}cnt1\mathrm{cnt_1}cnt\mathrm{cnt} 的关系。

不难发现 cnt1=cnt+1\mathrm{cnt_1 = cnt + 1}ans1=ans+cnt+1\mathrm{ans_1 = ans + cnt + 1}

再设 SS 进行一步操作二后,变为括号串 S2=(S)S_2 = \overline{\mathtt ( S\mathtt)},相应参数 ans2\mathrm{ans_2}cnt2\mathrm{cnt_2}

我们试图证明,新增的合法括号非空子串只有 S2\boldsymbol{S_2} 本身一个。

反证法,我们考虑有没有可能,新加的这对括号中的左括号,和 SS 的一段前缀组成一段合法括号子串?

很明显,这要求 SS 的这段前缀中,右括号比左括号多一个。

但在操作的变换中,字符串始终是合法括号串。因此,SS 不可能存在一段右括号比左括号多的前缀。

那有无可能,新加的这对括号中的右括号,和 SS 的一段后缀组成一段合法括号子串?

这要求 SS 的这段后缀里,左括号比右括号多一个。

可以发现,这就意味着 SS 除去这段后缀的剩余那部分前缀,右括号比左括号多一个(因为整个括号串左右括号数相等),所以同样不可能。

那么新增的合法括号子串只有 S2S_2 本身一个咯。

所以 cnt2=1\mathrm{cnt_2} = 1ans2=ans+1\mathrm{ans_2} = \mathrm{ans} + 1

现在考虑撤销操作。发现撤销操作对 cnt\mathrm{cnt}ans\mathrm{ans} 的变化并不平凡。

然后这里有一个比较不朴素的想法……那就是用矩阵刻画上面两种操作的变换。

刻画还是较为容易的:

[anscnt1]×[100110111]=[ans1cnt11]\begin{bmatrix}\mathrm{ans} & \mathrm{cnt} & \mathrm{1}\end{bmatrix} \times\begin{bmatrix}1 & 0 & 0\\1 & 1 & 0\\1 & 1 & 1\end{bmatrix} = \begin{bmatrix}\mathrm{ans_1} & \mathrm{cnt_1} & \mathrm{1}\end{bmatrix}

[anscnt1]×[100000111]=[ans2cnt21]\begin{bmatrix}\mathrm{ans} & \mathrm{cnt} & \mathrm{1}\end{bmatrix} \times\begin{bmatrix}1 & 0 & 0\\0 & 0 & 0\\1 & 1 & 1\end{bmatrix} = \begin{bmatrix}\mathrm{ans_2} & \mathrm{cnt_2} & \mathrm{1}\end{bmatrix}

那么答案可以看做初始矩阵 [111]\begin{bmatrix}1 & 1 & 1\end{bmatrix} 经过一系列矩阵乘法得到的结果。

那撤销是什么?题目的撤销还可以撤销一个撤销操作,看起来很高级,但它的影响最后无非都是:

  • 将某个非撤销操作(即操作一或操作二)从进行改为不进行。
  • 将某个非撤销操作(即操作一或操作二)从不进行改为进行。

不进行操作也是可以刻画出矩阵的,即单位矩阵 [100010001]\begin{bmatrix}1 & 0 & 0 \\0 & 1 & 0 \\ 0 & 0 & 1\end{bmatrix}

所以任何一个撤销操作都是将一个非撤销操作对应的矩阵单点修改,要么是从操作矩阵修改成单位矩阵,要么是从单位矩阵修改成操作矩阵。

因此现在变成一个对矩阵单点修改,求矩阵全局乘法的问题。因为矩阵乘法有结合律,可以用线段树维护。

因为矩阵乘法没法差分,所以不能用单 log\log 的树状数组。

时间复杂度 Θ(K3nlogn)\Theta(K^3 n \log n),其中 K=3K = 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;
}
posted @   dbxxx  阅读(75)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示