[NOI 2003] 文本编辑器 editor

文本编辑器
【问题描述】
很久很久以前,DOS3.x 的程序员们开始对 EDLIN 感到厌倦。于是,人们开始纷纷改用自己写的文本编辑器......
多年之后,出于偶然的机会,小明找到了当时的一个编辑软件。进行了一些简单的测试后,小明惊奇地发现:那个软件每秒能够进行上万次编辑操作(当然,你不能手工进行
这样的测试)!于是,小明废寝忘食地想做一个同样的东西出来。你能帮助他吗?
为了明确任务目标,小明对“文本编辑器”做了一个抽象的定义:
文本:由 0 个或多个字符构成的序列。这些字符的 ASCII 码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。
光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。
文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下六条操作的程序。
如果这段文本为空,我们就说这个文本编辑器是空的。
MOVE(k) Move k 将光标移动到第 k 个字符之后,如果 k=0,将光标移到文本第一个字符之前
INSERT(n, s) Insert n↵ S 在光标后插入长度为 n 的字符串 s,光标位置不变,n ≥ 1
DELETE(n) Delete n 删除光标后的 n 个字符,光标位置不变,n ≥ 1
GET(n) Get n 输出光标后的 n 个字符,光标位置不变,n ≥ 1
PREV() Prev 光标前移一个字符
NEXT() Next 光标后移一个字符
比如从一个空的文本编辑器开始,依次执行操作 INSERT(13,“Balanced□tree”),MOVE(2),DELETE(5),NEXT(),INSERT(7,“□editor”),MOVE(0),GET(15)后,会输出"Bad□editor□tree”,如下表所示:
|Balanced□tree
INSERT(13, | MOVE(2) |Balanced□tree Ba|lanced□tree“Balanced□tree”) 
DELETE(5) Ba|lanced□tree Ba|d□tree
NEXT() Ba|d□tree Bad|□tree
INSERT(7, Bad|□tree Bad|□editor□tree“□editor”), 
(只有光标,文本为空)
MOVE(0) Bad|□editor□tree |Bad□editor□tree
GET(15) |Bad□editor□tree 输出“Bad□editor□tree”
上表中,“|”表示光标,“□”表示空格。
你的任务是:
建立一个空的文本编辑器。
从输入文件中读入一些操作指令并执行。
对所有执行过的 GET 操作,将指定的内容写入输出文件。

这是一道 splay or 块链的裸题,如果使用 splay 的话,用根节点作为光标好了。其他所有操作都几乎是裸的。

然后有一些小细节未能注意,调了很久:

1.以为一次不会插入太多字符,于是开小了读入数组。

2.光标的数字在执行 next 时 ++, 而在执行 prev 时却 += 0 。。。(我 += 了一个 bool)

Code :

#include <cstdio>  
#include <cstdlib>  
#include <cstring>  
#include <map>  
#include <set>  
#include <queue>  
#include <algorithm>  
using namespace std;  
#define maxn 2100000  
struct node  
{  
    char k; int size;  
    node * c[2], * f;  
}   null[maxn], * ve[maxn], * root, * head, * tail;  
int T, n, tot, now;  
char ch, ss[maxn * 3 / 2];  
  
void rotate(node * p)  
{  
    node * q = p->f; bool k = p == q->c[1];  
    p->c[! k]->f = q, q->c[k] = p->c[! k], p->c[! k] = q;  
    q->f->c[q == q->f->c[1]] = p, p->f = q->f, q->f = p;  
    q->size = q->c[0]->size + q->c[1]->size + 1;  
}  
  
void splay(node * p, node * tar)  
{  
    while (p->f != tar)  
        if (p->f->f == tar) rotate(p);  
        else if ((p == p->f->c[0]) ^ (p->f == p->f->f->c[0])) rotate(p), rotate(p);  
        else rotate(p->f), rotate(p);  
    if (p->size = p->c[0]->size + p->c[1]->size + 1, tar == null) root = p;  
}  
  
node * getpos(int k)    // get the position of k  
{  
    if (k == 1) return head;  
    node * p = root; int rank = p->c[0]->size + 1;  
    for (; ; )  
        if (k == rank) return p;  
        else if (k < rank) p = p->c[0], rank -= p->c[1]->size + 1;  
        else p = p->c[1], rank += p->c[0]->size + 1;  
}  
  
node * move(node * p, bool k)   // for next or prev  
{  
    if (p->c[k] != null)  
        for (p = p->c[k]; p->c[! k] != null; p = p->c[! k]);  
    else  
    {  
        node * q;  
        for (q = p, p = p->f; q == p->c[k]; q = p, p = p->f);  
    }  
    return p;  
}  
  
node * newnode(char k, node * f)    // add new nodes  
{  
    node * p = ve[tot --]; p->k = k, p->size = 1, p->f = f;  
    if (p->c[0] != null) ve[++ tot] = p->c[0], p->c[0] = null;  
    if (p->c[1] != null) ve[++ tot] = p->c[1], p->c[1] = null;  
    return p;  
}  
  
node * build(int l, int r, node * f)    // prebalance the tree  
{  
    int mid = l + r >> 1;  
    node * p = newnode(ss[mid], f);  
    if (l < mid) p->c[0] = build(l, mid - 1, p);  
    if (mid < r) p->c[1] = build(mid + 1, r, p);  
    return f->size += p->size, p;  
}  
  
void dfs(node * p)  
{  
    if (p->c[0] != null) dfs(p->c[0]);  
    putchar(p->k);  
    if (p->c[1] != null) dfs(p->c[1]);  
}  
  
void show(node * p)  
{  
    if (p->c[0] != null) show(p->c[0]);  
    fprintf(stderr, "%c", p->k);  
    if (p->c[1] != null) show(p->c[1]);  
}  
  
int main()  
{  
    for (int i = tot = maxn - 1; i; -- i)  
        * (ve[i] = null + i) = (node) {0, 0, {null, null}, null};  
    root = head = newnode(0, null), tail = newnode(0, root);  
    root->c[1] = tail, ++ root->size;  
      
    for (scanf("%d", & T); T --; )  
        if (scanf("%s", ss), ss[0] == 'I')  
        {  
            scanf("%d", & n);  
            for (int i = 1; i <= n; ++ i)  
                if ((ch = getchar()) == '\n') -- i; else ss[i] = ch;  
            node * p = newnode(ss[n], root);  
            p->c[1] = root->c[1], root->c[1] = p, p->c[1]->f = p;  
            if (n - 1 > 0) p->c[0] = build(1, n - 1, p);  
            p->size = p->c[0]->size + p->c[1]->size + 1, root->size += n;  
        }  
        else if (ss[0] == 'M')  
            scanf("%d\n", & now), splay(getpos(now + 1), null);  
        else if (ss[0] == 'D')  
        {  
            scanf("%d", & n), splay(getpos(now + n + 2), root);  
            node * & p = root->c[1]->c[0]; ve[++ tot] = p;  
            root->c[1]->size -= p->size, root->size -= p->size, p = null;  
        }  
        else if (ss[0] == 'G')  
        {  
            scanf("%d", & n), splay(getpos(now + n + 2), root);  
            dfs(root->c[1]->c[0]), puts("");  
        }  
        else  
            splay(move(root, ss[0] == 'N'), null), ss[0] == 'N' ? ++ now : -- now;  
      
    return 0;  
}  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值