★★★   输入文件: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. 手机e.pageX和e.pageY无效的原因

    手机端拖拽事件: touchstart事件:当手指触摸屏幕时候触发,即使已经有一个手指放在屏幕上也会触发. touchmove事件:当手指在屏幕上滑动的时候连续地触发.在这个事件发生期间,调用prev ...

  2. [解决]WPF 在 win7 系统无法运行:FileNotFoundException

    开发环境:VS2015 + .NET 4.6.2 开发项目1:WPF + CefSharp 开发项目2:WPF 情况:两个项目编译的程序都无法在客户环境的 win7上运行,事件查看器中如下日志: Th ...

  3. (2.17)Mysql之SQL基础——日期函数

    关键词:mysql时间函数,mysql日期函数 [1]curdate():返回当前日期(2019-03-06),curdate()+0 返回(20190306) [2]curtime():返回当前时间 ...

  4. mysql 权限管理 针对表的字段 级别 授权 columns_priv表

    针对Mike账号 db1库下面的t1表的 id,name字段授予select权限,age字段授予update权限 授权格式 select(要授权的字段,要授权的字段) 用户括号 括起来  .updat ...

  5. css 常用的属性

    box-shadow: 10px 10px 5px #000000;  //给元素添加阴影 使用伪元素after要注意加上content属性 例如:.log:after{ content:" ...

  6. PHPExcel使用-使用PHPExcel导入文件

    导入步骤: 1. 实例化excel读取对象 2. 加载excel文件 ----------------> ( 1>. 全部加载. 2>. 选择加载. ) 3. 读取excel文件 - ...

  7. 安装HDF5及在VS下配置HDF5

    最近要用到HDF5来存储数据,想要安装尝试用一下.发现网上有两种安装方式,一种是obtain518.html:获取最新的HDF5-1.8软件;另一种是cmakebuild518.html:使用CMAK ...

  8. iptables 常用命令

    iptables service iptables save \\保存 iptables -F \\清空所有规则 iptables -F -t nat \\清空nat表 iptables -t nat ...

  9. java selenium webdriver处理JS操作窗口滚动条

    未经作者允许,禁止转载!!! java selenium webdriver处理JS操作窗口滚动条 java selenium webdriver处理JS操作窗口滚动条 import org.open ...

  10. iOS UI基础-5.0 QQ框架(Storyboard)

    1.拉入TabBarController和4个Navigation 2.TabBarController关联Navigation 3.设置消息,拉入一个Button,设置背影 4.联系人,拉入一个Se ...