★★★   输入文件:editor2003.in   输出文件:editor2003.out   简单对比
                      时间限制:2 s   内存限制:128 MB

【问题描述】

很久很久以前,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”,如下表所示:

操作

操作前的文本

操作后的结果

INSERT(13, "Balanced□tree")

|

(只有光标,文本为空)

|Balanced□tree

MOVE(2)

|Balanced□tree

Ba|lanced□tree

DELETE(5)

Ba|lanced□tree

Ba|d□tree

NEXT()

Ba|d□tree

Bad|□tree

INSERT(7, "□editor")

Bad|□tree

Bad|□editor□tree

MOVE(0)

Bad|□editor□tree

|Bad□editor□tree

GET(15)

|Bad□editor□tree

输出“Bad□editor□tree”

上表中,“|”表示光标,“□”表示空格。   你的任务是:

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

【输入文件】

输入文件的第一行是指令条数t,以下是需要执行的t个操作。其中:

为了使输入文件便于阅读,Insert操作的字符串中可能会插入一些回车符,请忽略掉它们(如果难以理解这句话,可以参考样例)。

除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。   这里我们有如下假定:

  • MOVE操作不超过50000个,INSERT和DELETE操作的总个数不超过4000,PREV和NEXT操作的总个数不超过200000。
  • 所有INSERT插入的字符数之和不超过2M(1M=1024*1024),正确的输出文件长度不超过3M字节。
  • DELETE操作和GET操作执行时光标后必然有足够的字符。MOVE、PREV、NEXT操作不会把光标移动到非法位置。
  • 输入文件没有错误。

对C++选手的提示:经测试,对最大的测试数据使用fstream进行输入有可能会比使用stdio慢约1秒,因此建议在可以的情况下使用后者。

【输出文件】

输出文件的每行依次对应输入文件中每条GET指令的输出。

【样例输入】

15
Insert 26
abcdefghijklmnop
qrstuv wxy
Move 15
Delete 11
Move 5
Insert 1
^
Next
Insert 1
_
Next
Next
Insert 4
.\/.
Get 4
Prev
Insert 1
^
Move 0
Get 22

【样例输出】

.\/. 
abcde^_^f.\/.ghijklmno

题解:
  本题用splay来维护,我们先在splay中插入两个'*'表示在序列的开端和结尾各有一个'*'方便以后处理,pos记录当前光标所在位置,因为在序列开头加上了'*',所以pos=光标所在的位置+1。
  对于插入操作,可以先把要插入的序列建成一棵splay,假设光标在第k个字符的后面,那么让第k-1个字符旋至根,第k个字符旋至根的右孩子,所要加入的区间就是根的右孩子的左边那一块,直接把刚建好的splay插入。
  删除操作就是找到要删除区间的左端点,把它旋至根,找到要删除区间的右端点,把它旋至根的右孩子,要删除的区间就是根的右孩子的左边那一块,直接删除即可。
  剩下的操作就是直接对pos的操作,很好理解。

 #include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn=;
int root,tot,fa[maxn],lc[maxn],rc[maxn],siz[maxn];
int T,N,pos=;
char opt[],ch[maxn],key[maxn];
inline void update(int x){
siz[x]=siz[lc[x]]++siz[rc[x]];
}
inline void r_rotate(int x){
int y=fa[x];
lc[y]=rc[x];
if(rc[x]) fa[rc[x]]=y;
fa[x]=fa[y];
if(y==lc[fa[y]]) lc[fa[y]]=x;
else rc[fa[y]]=x;
fa[y]=x; rc[x]=y;
update(y); update(x);
}
inline void l_rotate(int x){
int y=fa[x];
rc[y]=lc[x];
if(lc[x]) fa[lc[x]]=y;
fa[x]=fa[y];
if(y==lc[fa[y]]) lc[fa[y]]=x;
else rc[fa[y]]=x;
fa[y]=x; lc[x]=y;
update(y); update(x);
}
inline void splay(int x,int s){
int p;
while(fa[x]!=s){
p=fa[x];
if(fa[p]==s){
if(x==lc[p]) r_rotate(x);
else l_rotate(x);
break;
}
else if(x==lc[p]){
if(p==lc[fa[p]]) r_rotate(x),r_rotate(x);
else r_rotate(x),l_rotate(x);
}
else if(x==rc[p]){
if(p==rc[fa[p]]) l_rotate(x),l_rotate(x);
else l_rotate(x),r_rotate(x);
}
}
if(s==) root=x;
}
inline int find(int x,int rank){
if(siz[lc[x]]+==rank) return x;
else if(siz[lc[x]]+>rank) return find(lc[x],rank);
else return find(rc[x],rank-siz[lc[x]]-);
}
inline void split(int l,int r){
int x=find(root,l-),y=find(root,r+);
splay(x,); splay(y,root);
}
inline void newnode(int &x,char ch,int fath){
x=++tot;
fa[x]=fath; key[x]=ch;
lc[x]=rc[x]=; siz[x]=;
}
inline void insert(int &x,int l,int r,int fath){
int mid=(l+r)>>;
newnode(x,ch[mid],fath);
if(l+<=mid) insert(lc[x],l,mid-,x);
if(mid+<=r) insert(rc[x],mid+,r,x);
update(x);
}
inline void Delete(){
split(pos+,pos+N);
fa[lc[rc[root]]]=; lc[rc[root]]=;
update(rc[root]); update(root);
}
inline void print(int x){
if(lc[x]) print(lc[x]);
printf("%c",key[x]);
if(rc[x]) print(rc[x]);
}
inline void Get(){
split(pos+,pos+N);
print(lc[rc[root]]);
}
int main(){
newnode(root,'*',); newnode(rc[root],'*',root); update(root);
scanf("%d",&T);
while(T--){
scanf("%s",opt);
switch(opt[]){
case'M':
scanf("%d",&N);
pos=N+;
break;
case'I':
scanf("%d",&N);
for(int i=;i<=N;i++){
ch[i]=getchar();
while(ch[i]<||ch[i]>) ch[i]=getchar();
}
split(pos+,pos);//分割光标和光标的下一位
insert(lc[rc[root]],,N,rc[root]);
update(rc[root]); update(root);
break;
case'D':
scanf("%d",&N);
Delete();
break;
case'G':
scanf("%d",&N);
Get(); printf("\n");
break;
case'P':
pos--; break;
case'N':
pos++; break;
}
}
return ;
}
 

cogs 330. [NOI2003] 文本编辑器的更多相关文章

  1. [NOI2003] 文本编辑器 (splay)

    复制炸格式了,就不贴题面了 [NOI2003] 文本编辑器 Solution 对于光标的移动,我们只要记录一下现在在哪里就可以了 Insert操作:手动维护中序遍历结果,即每次取中点像线段树一样一样递 ...

  2. 洛谷 P4008 [NOI2003]文本编辑器 解题报告

    P4008 [NOI2003]文本编辑器 题目描述 很久很久以前,\(DOS3.x\)的程序员们开始对 \(EDLIN\) 感到厌倦.于是,人们开始纷纷改用自己写的文本编辑器⋯⋯ 多年之后,出于偶然的 ...

  3. [NOI2003]文本编辑器 [Fhq Treap]

    [NOI2003]文本编辑器 没啥好说的 就是个板子 #include <bits/stdc++.h> // #define int long long #define rep(a , b ...

  4. luogu P4008 [NOI2003]文本编辑器 splay 块状链表

    LINK:文本编辑器 这个东西感觉块状链表写细节挺多 (块状链表本来就难写 解释一下块状链表的做法:其实是一个个数组块 然后利用链表给链接起来 每个块的大小为sqrt(n). 这样插入删除的时候直接暴 ...

  5. NOI2003 文本编辑器editor

    1507: [NOI2003]Editor Time Limit: 5 Sec  Memory Limit: 162 MBSubmit: 1908  Solved: 738[Submit][Statu ...

  6. NOI2003 文本编辑器

    练手QAQ #include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib& ...

  7. 题解 P4008 【[NOI2003]文本编辑器】

    块状链表及其应用 思路楼上已经说的很清楚了 看代码注释 代码很丑 #include<cstdio> #include<cctype> #include<cstring&g ...

  8. P4008 [NOI2003]文本编辑器

    思路 FHQ Treap的板子 用FHQ Treap维护中序遍历序列即可 然后数组开够! 代码 #include <cstdio> #include <cstring> #in ...

  9. 【洛谷 P4008】 [NOI2003]文本编辑器 (Splay)

    题目链接 \(Splay\)先练到这吧(好像还有道毒瘤的维护数列诶,算了吧) 记录下光标的编号,维护就是\(Splay\)基操了. 另外数据有坑,数据是\(Windows\)下生成了,回车是'\n\r ...

随机推荐

  1. 【Git 使用笔记】第四部分:git在公司中的开发流程

    先声明几个变量 仓管A:主分支,只有master分支仓管B:开发分支,只有各个业务开发分支   仓管B fork 于 A 如下图 为了保证 代码的稳定性,只有 仓管B中的某个分支测试完毕并进行了代码r ...

  2. Spring Data JPA(官方文档翻译)

    关于本书 介绍 关于这本指南 第一章 前言 第二章 新增及注意点 第三章 项目依赖 第四章 使用Spring Data Repositories 4.1 核心概念 4.2 查询方法 4.3 定义rep ...

  3. nautilus

    在~/.bashrc中定义命令别名,添加以下命令: # some more nautilus aliases alias here='nautilus . > /dev/null 2>&a ...

  4. jquery表格展示

    用bootstrap设计一个弹框,然后在弹框里面生成表格 <html> <head> <link rel="stylesheet" href=&quo ...

  5. java数据库三大范式

    引用知乎网友@ 王红波的回答 一范式就是属性不可分割.属性是什么?就是表中的字段.不可分割的意思就按字面理解就是最小单位,不能再分成更小单位了.这个字段只能是一个值,不能被拆分成多个字段,否则的话,它 ...

  6. 【爬坑】python3+pyqt5+pyinstaller 打包成exe的各种问题

    windows系统+python3+pyqt5+pyinstaller打包,经常会出现各种打包异常情况.如果代码没有特别异常,那么综合原因,大抵都是这四个元素之间的匹配问题,引起的.作者:一心狮链接: ...

  7. 迁移到 Linux :入门介绍 | Linux 中国

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/F8qG7f9YD02Pe/article/details/79001952 这个新文章系列将帮你从其 ...

  8. 十天精通CSS3(7)

    :enabled选择器 在Web的表单中,有些表单元素有可用(“:enabled”)和不可用(“:disabled”)状态,比如输入框,密码框,复选框等.在默认情况之下,这些表单元素都处在可用状态.那 ...

  9. 十天精通CSS3(1)

    什么是CSS3? CSS3是CSS2的升级版本,3只是版本号,它在CSS2.1的基础上增加了很多强大的新功能. 目前主流浏览器chrome.safari.firefox.opera.甚至360都已经支 ...

  10. [vue]vue条件渲染v-if(template)和自定义指令directives

    条件渲染: v-if/template <div id="app"> <h1>v-show: display: none</h1> <di ...