【BZOJ 1269】文本编辑器

题目

这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器。你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义:

  • Move k:将光标移动到第 \(k\) 个字符之后,如果 \(k=0\) , 将光标移到文本第一个字符之前。(注意是 cur = k 不是 cur += k)
  • Insert n (换行) S:在光标后插入长度为n的字符串S,光标位置不变,\(n\ge 1​\)
  • Delete n:删除光标后的 \(n\) 个字符,光标位置不变,\(n\ge 1\)
  • Rotate n:反转光标后的 \(n​\) 个字符,光标位置不变,\(n\ge 1​\)
  • Get:输出光标后的一个字符,光标位置不变。
  • Prev:光标前移一个字符。
  • Next:光标后移一个字符。

下面是几个定义:

  • 文本:由0个或多个字符构成的序列。这些字符的 ASCII 码在闭区间 [32, 126] 内,也就是说,这些字符均为可见字符或空格。
  • 光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。
  • 文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下七条操作的程序。如果这段文本为空,我们就说这个文本编辑器是空的。

编写一个程序:

  1. 建立一个空的文本编辑器。
  2. 从输入文件中读入一些操作指令并执行。
  3. 对所有执行过的 Get 操作,将指定的内容写入输出文件。

分析

发现一堆人的 Splay 是用 split 和 merge 做的, 然而我觉得既然写了 Splay, 为什么不用 Splay 呢?

试图掩盖我不会写这两操作的事实

重点在 Delete/Insert/Rotate 操作上.(下方 \(c\) 为光标的后一个字符的位置)

  • Insert n S: 把 \(c - 1​\)\(c​\) 分别旋转到根节点和根节点的右孩子, 此时根节点的右孩子的左孩子就代表了区间 \((c-1, c)​\), 显然该区间为空, 用之前的建树去做就可以了.
  • Delete n: 把 \(c - 1\)\(c + n\) 旋转到根节点的右孩子, 此时根节点的右孩子的左孩子就代表了区间 \((c - 1, c + n )\), 即 \([c, c + n - 1]​\), 随便删除即可.
  • Rotate n: 把 \(c - 1\)\(c + n\) 旋转到根节点的右孩子, 此时根节点的右孩子的左孩子就代表了区间 \((c - 1, c + n )\), 即 \([c, c + n - 1]\), 随便翻转即可.

然后随便写写就好了, 似乎也没有考虑讨论中说的毒瘤输入就过了...

代码

跑的似乎还很快? (\(1.8\ s\)).

#include <bits/stdc++.h>

#define fa(x) t[x].fa
#define siz(x) t[x].siz
#define val(x) t[x].val
#define tag(x) t[x].tag
#define child(x, y) t[x].child[y]
#define rt t[1].child[1]

const int kMaxSize = 2e6 + 5;

struct node {
    int child[2], fa, siz; char val; bool tag;
} t[kMaxSize];
int cnt = 2;
inline void Cnct(int c, int f, int p) {fa(c) = f; child(f, p) = c;}
inline void Updata(int x) {siz(x) = siz(child(x, 0)) + siz(child(x, 1)) + 1;}
inline bool Which(int x) {return x == child(fa(x), 1);}
inline int NewNode(char val, int fa) {fa(cnt) = fa; val(cnt) = val; return cnt++;}
void PushTag(int x) {
    if(tag(x)) {
        child(x, 0) ^= child(x, 1) ^= child(x, 0) ^= child(x, 1);
        tag(child(x, 0)) ^= 1; tag(child(x, 1)) ^= 1;
        tag(x) = false;
    }
}
void Rotate(int &x) {
    int gfa = fa(fa(x)); bool p = Which(x), pfa = Which(fa(x));
    Cnct(child(x, p ^ 1), fa(x), p); Cnct(fa(x), x, p ^ 1); Cnct(x, gfa, pfa);
    Updata(child(x, p ^ 1)); Updata(x);
}
void Splay(int cur, int to = 1) {
    for(; fa(cur) != to; Rotate(cur)) {
        if(fa(fa(cur)) != to)
            Which(cur) == Which(fa(cur)) ? Rotate(fa(cur)) : Rotate(cur);
    }
}
void Build(int &cur, int fa, int l, int r, std::string &a) {
    if(l <= r) {
        int mid = (l + r) >> 1;
        cur = NewNode(a[mid], fa);
        Build(child(cur, 0), cur, l, mid - 1, a);
        Build(child(cur, 1), cur, mid + 1, r, a);
        Updata(cur);
    }
}
void Output(int cur = rt) {
    if(!cur) return;
    PushTag(cur);
    Output(child(cur, 0));
    if(val(cur)) printf("%c", val(cur));
    Output(child(cur, 1));
}
int FindKth(int k) {
    for(int cur = rt, tot = 0; ; tot++) {
        PushTag(cur);
        if(k == siz(child(cur, 0)) + 1) return cur;
        else if(k <= siz(child(cur, 0))) cur = child(cur, 0);
        else k -= siz(child(cur, 0)) + 1, cur = child(cur, 1);
    }
}
void Reverse(int x, int n) {
    Splay(FindKth(x - 1)); Splay(FindKth(x + n), rt);
    tag(child(child(rt, 1), 0)) ^= 1;
}
void Insert(int x, int ptr) { 
    Splay(FindKth(x - 1)); Splay(FindKth(x), rt);
    Cnct(ptr, child(rt, 1), 0);
    Updata(child(rt, 1)); Updata(rt);
}
void Delete(int x, int n) {
    Splay(FindKth(x - 1)); Splay(FindKth(x + n), rt);
    child(child(rt, 1), 0) = 0;
    Updata(child(rt, 1)); Updata(rt);
}

using std::cout;
using std::cin;

int q, curt = 2; std::string s;
int main() {
    std::ios::sync_with_stdio(false);
    cin >> q;
    s[1] = s[2] = 0;
    Build(rt, 1, 1, 2, s);
    while(q--) {
        std::string opt, str; int n;
        cin >> opt;
        if(opt == "Move") {
            cin >> n;
            if(n == 0) curt = 2;
            else curt = n + 2;
        } else if(opt == "Insert") {
            cin >> n;
            cin.ignore();
            getline(cin, str);
            str = " " + str;
            int ptr;
            Build(ptr, 1, 1, n, str);
            Insert(curt, ptr);
        } else if(opt == "Delete") {
            cin >> n;
            Delete(curt, n);
        } else if(opt == "Rotate") {
            cin >> n;
            Reverse(curt, n);
        } else if(opt == "Get") {
            int ptr = FindKth(curt);
            Splay(ptr);
            cout << val(ptr) << std::endl;
        } else if(opt == "Prev") curt--;
        else if(opt == "Next") curt++;
    }
    return 0;

}

猜你喜欢

转载自www.cnblogs.com/zhylj/p/10381075.html