NC16901. [NOI2003]文本编辑器
描述
很久很久以前,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 | 光标后移一个字符 |
输入描述
的第一行是指令条数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操作必然不会试图把光标移动到非法位置。
输入文件没有错误。
输出描述
每行依次对应输入文件中每条Get 指令的输出。
示例1
输入:
15 Insert 26 abcdefghijklmnop qrstuv wxy Move 16 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
C++14(g++5.4) 解法, 执行用时: 1381ms, 内存消耗: 39040K, 提交时间: 2019-06-11 14:21:30
#include<bits/stdc++.h> #define MAXN 2000010 #define LL long long int #define FIO ios::sync_with_stdio(false) #define FRD freopen("input.txt","r",stdin) const LL MOD=1e9+10; using namespace std; int f[MAXN],cnt[MAXN],ch[MAXN][2],size[MAXN],sz,rt,pt=0; char key[MAXN]; void clear(int x){ f[x]=cnt[x]=ch[x][0]=ch[x][1]=size[x]=key[x]=0; } bool get(int x){ return ch[f[x]][1]==x; } void pushup(int x){ if (x){ size[x]=cnt[x]; if (ch[x][0]) size[x]+=size[ch[x][0]]; if (ch[x][1]) size[x]+=size[ch[x][1]]; } } void rotate(int x){ int old=f[x],oldf=f[old],which=get(x); ch[old][which]=ch[x][which^1]; f[ch[old][which]]=old; ch[x][which^1]=old; f[old]=x; f[x]=oldf; if (oldf) ch[oldf][ch[oldf][1]==old]=x; pushup(old); pushup(x); } void splay(int x){ for (int fa; fa=f[x]; rotate(x)) if (f[fa]) rotate((get(x)==get(fa))?fa:x); rt=x; } void insert(char x){ if(rt==0){ sz++;key[sz]=x;rt=sz; cnt[sz]=size[sz]=1; f[sz]=ch[sz][1]=ch[sz][0]=0; return; } sz++; ch[sz][1]=ch[rt][1];f[ch[rt][1]]=sz; ch[rt][1]=sz;f[sz]=rt; cnt[sz]=1; key[sz]=x; pushup(sz);pushup(rt); } int kth(int x){ int now=rt; while (1){ if (ch[now][0] && x<=size[ch[now][0]]) now=ch[now][0]; else{ int temp=size[ch[now][0]]+cnt[now]; if (x<=temp) return now; x-=temp; now=ch[now][1]; } } } int pre(){ int now=ch[rt][0]; while (ch[now][1]) now=ch[now][1]; return now; } int next(){ int now=ch[rt][1]; while (ch[now][0]) now=ch[now][0]; return now; } void del(){ if (cnt[rt]>1) {cnt[rt]--; pushup(rt); return;} if (!ch[rt][0] && !ch[rt][1]) {clear(rt); rt=0; return;} if (!ch[rt][0]) { int oldrt=rt; rt=ch[rt][1]; f[rt]=0; clear(oldrt); return; } else if (!ch[rt][1]) { int oldrt=rt; rt=ch[rt][0]; f[rt]=0; clear(oldrt); return; } int oldrt=rt; int leftbig=pre(); splay(leftbig); ch[rt][1]=ch[oldrt][1]; f[ch[oldrt][1]]=rt; clear(oldrt); pushup(rt); } void init(){ for(int i=1;i<=sz;i++) clear(i); sz=0; rt=0; } void MOVE(int k){ pt=kth(k+1); } void DELETE(int n){ splay(pt); for(int i=0;i<n;i++){ splay(next()); //cout<<key[rt]<<endl; del(); } } void GET(int n){ splay(pt); for(int i=0;i<n;i++){ splay(next()); cout<<key[rt]; } cout<<endl; } void PREV(){ splay(pt); pt=pre(); } void NEXT(){ splay(pt); pt=next(); } void INSERT(string &str){ splay(pt); for(int i=str.size()-1;i>=0;i--){ insert(str[i]); } } int main(){ //FRD; FIO; insert('!'); insert('$'); pt=1; int q; cin>>q; while(q--){ string str; cin>>str; if(str=="Insert"){ int n; cin>>n; splay(pt); int tot=0; string str=""; while(tot<n){ string tmp; getline(cin,tmp); tot+=tmp.size(); str+=tmp; } INSERT(str); } else if(str=="Move"){ int n; cin>>n; MOVE(n); } else if(str=="Delete"){ int n; cin>>n; DELETE(n); } else if(str=="Next"){ NEXT(); } else if(str=="Prev"){ PREV(); } else if(str=="Get"){ int n; cin>>n; GET(n); } //cout<<key[pt]<<endl; } return 0; }
C++(clang++ 11.0.1) 解法, 执行用时: 1294ms, 内存消耗: 22984K, 提交时间: 2022-09-29 23:39:19
#include <iostream> #include <cstring> #include <cstdio> #include <ext/rope> using namespace __gnu_cxx; using namespace std; rope <char> editor; char ch; string oper; int pos, n, rela; int main(){ cin.tie(0); cout.tie(0); scanf("%d", &n); while(n--){ cin >> oper; scanf("%d", &rela); if(oper =="Insert"){ int pos1 = pos; while(rela){ ch = getchar(); if((int)ch >= 32 && (int)ch <= 126){ editor.insert(pos1, ch); rela--; pos1++; } } } else if(oper =="Move") pos = rela; else if(oper =="Next") pos++; else if(oper =="Prev") pos--; else if(oper =="Get") cout << editor.substr(pos, rela) << endl; else if(oper =="Delete") editor.erase(pos, rela); } return 0; }