cogs 330. [NOI2003] 文本编辑器
★★★ 输入文件: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] 文本编辑器的更多相关文章
- [NOI2003] 文本编辑器 (splay)
复制炸格式了,就不贴题面了 [NOI2003] 文本编辑器 Solution 对于光标的移动,我们只要记录一下现在在哪里就可以了 Insert操作:手动维护中序遍历结果,即每次取中点像线段树一样一样递 ...
- 洛谷 P4008 [NOI2003]文本编辑器 解题报告
P4008 [NOI2003]文本编辑器 题目描述 很久很久以前,\(DOS3.x\)的程序员们开始对 \(EDLIN\) 感到厌倦.于是,人们开始纷纷改用自己写的文本编辑器⋯⋯ 多年之后,出于偶然的 ...
- [NOI2003]文本编辑器 [Fhq Treap]
[NOI2003]文本编辑器 没啥好说的 就是个板子 #include <bits/stdc++.h> // #define int long long #define rep(a , b ...
- luogu P4008 [NOI2003]文本编辑器 splay 块状链表
LINK:文本编辑器 这个东西感觉块状链表写细节挺多 (块状链表本来就难写 解释一下块状链表的做法:其实是一个个数组块 然后利用链表给链接起来 每个块的大小为sqrt(n). 这样插入删除的时候直接暴 ...
- NOI2003 文本编辑器editor
1507: [NOI2003]Editor Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 1908 Solved: 738[Submit][Statu ...
- NOI2003 文本编辑器
练手QAQ #include<iostream> #include<algorithm> #include<cstdio> #include<cstdlib& ...
- 题解 P4008 【[NOI2003]文本编辑器】
块状链表及其应用 思路楼上已经说的很清楚了 看代码注释 代码很丑 #include<cstdio> #include<cctype> #include<cstring&g ...
- P4008 [NOI2003]文本编辑器
思路 FHQ Treap的板子 用FHQ Treap维护中序遍历序列即可 然后数组开够! 代码 #include <cstdio> #include <cstring> #in ...
- 【洛谷 P4008】 [NOI2003]文本编辑器 (Splay)
题目链接 \(Splay\)先练到这吧(好像还有道毒瘤的维护数列诶,算了吧) 记录下光标的编号,维护就是\(Splay\)基操了. 另外数据有坑,数据是\(Windows\)下生成了,回车是'\n\r ...
随机推荐
- automation轻松“一点”,搞定裸机安装系统
企业在新建数据中心.新业务上线.老业务扩容等场景下,会采购一批新的裸机服务器,在新服务器投入使用之前,势必得进行操作系统的安装.相信每个人都有安装操作系统的经历,BIOS设置.磁盘分区.驱动安装... ...
- [python-opencv]模板匹配
模板匹配最适用于工业场合(在一张图片中识别特定的工件图) 模板匹配是一种最原始.最基本的模式识别方法,研究某一特定对象物的图案位于图像(target)的什么地方,进而识别对象物,这就是一个匹配问题. ...
- Memcached集群架构方面的问题(转)
add by zhj: 这是一个系列中的第二篇,该系列有四篇,英文原文没找到,译文见:http://blog.csdn.net/jarfield/article/details/4336035 ,附上 ...
- shell date 获取昨天日期
使用date -d 选项: date +"%Y%m%d" -d "+n days" 今天的后n天日期 date +" ...
- PHP操作Redis常用技巧
这篇文章主要介绍了PHP操作Redis常用技巧,结合实例形式总结分析了php针对redis的连接.认证.string.hash等操作技巧与注意事项,需要的朋友可以参考下 本文实例讲述了PHP操作Red ...
- Oracal 11 g 数据库安装
一:下载安装包 http://www.oracle.com/technetwork/cn/database/enterprise-edition/downloads/112010-win64soft- ...
- 软件包管理:rpm命令管理-包命名与依赖性
rpm包的管理主要有两种方法:一种是rpm命令管理另一种是yum在线管理 注意软件包没有扩展名,写上只是为了好看,便于识别而已. 注意区别包名,包全名.之所以要区分,就是因为有些命令十分挑剔,需要跟正 ...
- 非线性方程(组):MATLAB内置函数 solve, vpasolve, fsolve, fzero, roots [MATLAB]
MATLAB函数 solve, vpasolve, fsolve, fzero, roots 功能和信息概览 求解函数 多项式型 非多项式型 一维 高维 符号 数值 算法 solve 支持,得到全部符 ...
- Django初级手册5-自动化测试
什么是自动化测试 每次更新完系统后,可自动进行测试,而不是手工从头测试一遍: 从长远和全局的角度看,测试能节约我们的时间: 测试是一种积极的行为,它能预防问题,而不仅仅是识别问题: 测试有助于代码美观 ...
- JSP—中文乱码
中文乱码问题? --------------------------------------- 不乱码的条件: 1.JSP页面本身的编码 pageEncoding UTF-8 (把jsp页面翻译成ja ...