1507: [NOI2003]Editor
Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 3397 Solved: 1360
[Submit][Status][Discuss]
Description
Input
输入文件editor.in的第一行是指令条数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秒。
Output
输出文件editor.out的每行依次对应输入文件中每条GET指令的输出。
Sample Input
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
Sample Output
abcde^_^f.\/.ghijklmno
HINT
Source
Solution
有块状链表和平衡树两种做法。
这里用来练块状链表。
Insert和Delete操作都是现将起始两块分裂,然后加入/拿掉中间的块
注意在Insert和Delete操作后要进行一次合并,防止退化成普通链表。
这题数据范围可能比较大,考虑写个内存池
这题把块的大小控制在3500大概能跑到640ms...
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<queue> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();} while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();} return x*f; } #define MAXN 2000010 #define Bsize 3500 #define Bnum MAXN/Bsize*3 char S[MAXN]; int loc; namespace BlockLists { struct BlockListsNode{char data[Bsize+111]; int size,next; }B[Bnum+1010]; int sz,start; queue<int>trash; inline int New() {if (trash.empty()) return ++sz; int tmp=trash.front(); trash.pop(); return tmp;} inline void Del(int x) {trash.push(x);} inline int GetP(int rk) {for (int i=start; ~i; i=B[i].next) if (rk>B[i].size) rk-=B[i].size; else return i;} inline int GetK(int rk) {for (int i=start; ~i; i=B[i].next) if (rk>B[i].size) rk-=B[i].size; else return rk;} inline void Data(int pos,int len,char data[],int suf) {B[pos].next=suf; B[pos].size=len; memcpy(B[pos].data,data,len);} inline void Split(int pos,int rk) { if (B[pos].size==rk) return; int id=New(); Data(id,B[pos].size-rk,B[pos].data+rk,B[pos].next); B[pos].next=id; B[pos].size=rk; } inline void Merge(int pos) { for ( ; ~pos; pos=B[pos].next) for (int suf=B[pos].next; ~suf && B[pos].size+B[suf].size<Bsize; suf=B[suf].next) memcpy(B[pos].data+B[pos].size,B[suf].data,B[suf].size),B[pos].size+=B[suf].size,B[pos].next=B[suf].next,Del(suf); } inline void Insert(int s,int len) { int now=GetP(s),pos=GetK(s),l,id; Split(now,pos); for (l=0; l+Bsize<=len; l+=Bsize) id=New(),Data(id,Bsize,S+l,B[now].next),B[now].next=id,now=id; if (l<len) id=New(),Data(id,len-l,S+l,B[now].next),B[now].next=id; Merge(now); } inline void Delete(int s,int len) { int now=GetP(s),pos=GetK(s),p; Split(now,pos); for (p=B[now].next; ~p; p=B[p].next) if (len>B[p].size) len-=B[p].size; else break; Split(p,len); p=B[p].next; for (int i=B[now].next; i!=p && ~i; i=B[now].next) B[now].next=B[i].next,Del(i); Merge(now); } inline void GetAns(int s,int len) { int now=GetP(s),pos=GetK(s),p,l; l=min(len,B[now].size-pos); memcpy(S,B[now].data+pos,l); for (p=B[now].next; ~p && l+B[p].size<=len; p=B[p].next) memcpy(S+l,B[p].data,B[p].size),l+=B[p].size; if (l<len && ~p) memcpy(S+l,B[p].data,len-l); S[len]=0; puts(S); } inline void Init() {start=0,B[0].size=0,B[0].next=-1;} } using namespace BlockLists; inline void GetS(int len) {int l=-1; while (l<len-1) {S[++l]=getchar(); if (S[l]<32 || S[l]>126) l--;}} int main() { // freopen("editor2003.in","r",stdin); // freopen("editor2003.out","w",stdout); int T=read(); BlockLists::Init(); while (T--) { char opt[20]; scanf("%s",opt); int x; switch (opt[0]) { case 'M': loc=read(); break; case 'I': x=read(); GetS(x); BlockLists::Insert(loc,x); break; case 'D': x=read(); BlockLists::Delete(loc,x); break; case 'G': x=read(); BlockLists::GetAns(loc,x); break; case 'P': loc--; break; case 'N': loc++; break; } } return 0; }
说起来太容易了,
昨晚接近3个小时手写模板,然后各种问题...最后还是借鉴了 将狼踩尽 大神的模板