题解:Luogu_P1383_高级打字机

题解:Luogu_P1383_高级打字机

Luogu_P1383_高级打字机
可持久化线段树

Solution

首先看到有撤销操作,想到用可持久化线段树维护,建树时直接用 \(1\sim m\) 区间建,每个节点存一个字符和 \(siz\),用于找下标。

  • 新增节点:在对应位置新增,记录 \(siz\),记得 \(pushup\),如果左子树 \(siz\) 等于 \(mid-l+1\),那么说明左子树满了,递归右子树
  • 撤销操作:直接新建一个当前版本的根指向撤销操作的根
  • 查询操作:按照 \(siz\),慢慢找

Code

记得把数组开大一点!!!

//P1383 (AC)

#include <iostream>
using namespace std;

const int N = 1e6 + 5;

int n, m, rnt, root[N];

struct node
{
    int ls, rs, siz;
    char val;

    node(int _ls = 0, int _rs = 0, int _siz = 0, char _val = ' ')
    {
        ls = _ls, rs = _rs, siz = _siz, val = _val;
    }
} t[N << 2];

int update(int rt, int l, int r, char val)
{
    int p = ++ n;
    t[p] = t[rt];
    if (l == r)
    {
        t[p].val = val;
        t[p].siz = 1;
        return p;
    }
    int mid = l + r >> 1;
    if (t[t[p].ls].siz >= mid - l + 1)
        t[p].rs = update(t[rt].rs, mid + 1, r, val);
    else
        t[p].ls = update(t[rt].ls, l, mid, val);
    t[p].siz = t[t[p].ls].siz + t[t[p].rs].siz;
    return p;
}

char query(int p, int l, int r, int pos)
{
    if (l >= r)
        return t[p].val;
    int mid = l + r >> 1;
    if (pos <= t[t[p].ls].siz)
        return query(t[p].ls, l, mid, pos);
    else
        return query(t[p].rs, mid + 1, r, pos - t[t[p].ls].siz);
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    cin >> m;
    char opt, ch;
    for (int val, i = 1; i <= m; i ++)
    {
        cin >> opt;
        if (opt == 'T')
        {
            cin >> ch;
            rnt ++;
            root[rnt] = update(root[rnt - 1], 1, m, ch);
            continue;
        }
        if (opt == 'U')
        {
            cin >> val;
            rnt ++;
            root[rnt] = root[rnt - val - 1];
            continue;
        }
        if (opt == 'Q')
        {
            cin >> val;
            cout << query(root[rnt], 1, m, val) << endl;
        }
    }

    return 0;
}
posted @ 2025-02-05 19:53  nueryim  阅读(16)  评论(0)    收藏  举报