1269: [AHOI2006]文本编辑器editor
Description
这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器。你能帮助他吗?为了明确任务目标,可可对“文本编辑器”做了一个抽象的定义:
文本:由0个或多个字符构成的序列。这些字符的ASCII码在闭区间[32, 126]内,也就是说,这些字符均为可见字符或空格。光标:在一段文本中用于指示位置的标记,可以位于文本的第一个字符之前,文本的最后一个字符之后或文本的某两个相邻字符之间。文本编辑器:为一个可以对一段文本和该文本中的一个光标进行如下七条操作的程序。如果这段文本为空,我们就说这个文本编辑器是空的。 编写一个程序: 建立一个空的文本编辑器。 从输入文件中读入一些操作指令并执行。 对所有执行过的GET操作,将指定的内容写入输出文件。
Input
输入文件中第一行是指令条数N,以下是需要执行的N个操作。除了回车符之外,输入文件的所有字符的ASCII码都在闭区间[32, 126]内。且行尾没有空格。
Output
依次对应输入文件中每条GET指令的输出,不得有任何多余的字符。
Sample Input
10
Insert 13
Balanced eert
Move 2
Delete 5
Next
Insert 7
editor
Move 0
Get
Move 11
Rotate 4
Get
Sample Output
B
t
【解题报告】
听闻了非常6的rope。
由于rope的底层实现,insert,erase,get都是logn的 就是翻转不行,不是自己手写的打不了标记啊!! 怎么办?
答:同时维护一正一反两个rope……反转即交换两个子串……Orz…… 区间循环位移?简单,拆成多个子串连起来就好了…… 区间a变b b变c
c变d …… z变a? 呃……维护26个rope? 区间和?滚蛋,那是线段树的活
区间kth?sorry,与数值有关的操作rope一概不支持…… 函数 功能 push_back(x) 在末尾添加x
insert(pos,x) 在pos插入x erase(pos,x) 从pos开始删除x个 replace(pos,x) 从pos开始换成x
substr(pos,x) 提取pos开始x个 at(x)/[x] 访问第x个元素
代码如下:
#include<cstdio>
#include<iostream>
#include<ext/rope>
#include<algorithm>
using namespace std;
using namespace __gnu_cxx;
int n,now,len;
rope <char> a,b,tmp;
char s[2000000],rs[2000000];
int main()
{
scanf("%d",&n);
int x;
while(n--)
{
scanf("%s",s);
switch(s[0])
{
case'M':scanf("%d",&now);break;
case'P':now--;break;
case'N':now++;break;
case'G':printf("%c\n",a[now]);break;
case'I':
{
scanf("%d",&x);len=a.length();
for(int i=0;i<x;++i)
{
s[i]=getchar();
while(s[i]=='\n') s[i]=getchar();
rs[x-i-1]=s[i];
}
rs[x]=s[x]=0;
a.insert(now,s);
b.insert(len-now,rs);
break;
}
case 'D':
{
scanf("%d",&x);len=a.length();
a.erase(now,x);
b.erase(len-now-x,x);
break;
}
case 'R':
{
scanf("%d",&x);len=a.length();
tmp=a.substr(now,x);
a=a.substr(0,now)+b.substr(len-now-x,x)+a.substr(now+x,len-now-x);
b=b.substr(0,len-now-x)+tmp+b.substr(len-now,now);
break;
}
}
}
return 0;
}
不过还是可以用SPLAY
来自http://www.cnblogs.com/kuangbin/archive/2013/08/27/3284085.html
/* ***********************************************
Author :kuangbin
Created Time :2013/8/26 22:47:15
File Name :F:\2013ACM练习\专题学习\splay_tree_2\文本编辑器editor.cpp
************************************************ */
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <time.h>
using namespace std;
/*
* 对字符串进行插入、删除、反转、查询第k个字符等操作
* Move k : 将光标移到到第k个字符之后
* Insert n S : 在光标后插入长度为n的字符串S,光标位置不变
* Delete n :删除光标后的n个字符,光标位置保持不变
* Rotate n :反转光标后的n个字符,光标位置不变
* Get :输出光标后的一个字符
* Prev :光标前移一个字符
* Next :光标后移一个字符
*
*
*用一个变量记录光标位置,对于Move,Prev,Next 直接改变这个变量
*
*/
#define Key_value ch[ch[root][1]][0]
const int MAXN = 2*1024*1024+10;
int ch[MAXN][2],pre[MAXN],rev[MAXN],size[MAXN];
int root,tot1;
char key[MAXN];
int s[MAXN],tot2;
int pos;//光标位置
char str[MAXN];//需要插入的字符串
void NewNode(int &r,int father,char k)
{
if(tot2) r = s[tot2--];
else r = ++tot1;
ch[r][0] = ch[r][1] = 0;
pre[r] = father;
rev[r] = 0;
key[r] = k;
size[r] = 1;
}
void Update_Rev(int r)
{
if(!r)return;
swap(ch[r][0],ch[r][1]);
rev[r] ^= 1;
}
void push_up(int r)
{
size[r] = size[ch[r][0]] + size[ch[r][1]] + 1;
}
void push_down(int r)
{
if(rev[r])
{
Update_Rev(ch[r][0]);
Update_Rev(ch[r][1]);
rev[r] = 0;
}
}
void Build(int &x,int l,int r,int father)
{
if(l > r)return;
int mid = (l+r)/2;
NewNode(x,father,str[mid]);
Build(ch[x][0],l,mid-1,x);
Build(ch[x][1],mid+1,r,x);
push_up(x);
}
void Init()
{
pos = 0;
root = tot1 = tot2 = 0;
ch[root][0] = ch[root][1] = pre[root] = size[root] = rev[root] = 0;
NewNode(root,0,' ');
NewNode(ch[root][1],root,' ');
push_up(ch[root][1]);
push_up(root);
}
void Rotate(int x,int kind)
{
int y = pre[x];
push_down(y);
push_down(x);
ch[y][!kind] = ch[x][kind];
pre[ch[x][kind]] = y;
if(pre[y])
ch[pre[y]][ch[pre[y]][1]==y] = x;
pre[x] = pre[y];
ch[x][kind] = y;
pre[y] = x;
push_up(y);
}
void Splay(int r,int goal)
{
push_down(r);
while(pre[r] != goal)
{
if(pre[pre[r]] == goal)
{
push_down(pre[r]);
push_down(r);
Rotate(r,ch[pre[r]][0]==r);
}
else
{
push_down(pre[pre[r]]);
push_down(pre[r]);
push_down(r);
int y = pre[r];
int kind = ch[pre[y]][0]==y;
if(ch[y][kind] == r)
{
Rotate(r,!kind);
Rotate(r,kind);
}
else
{
Rotate(y,kind);
Rotate(r,kind);
}
}
}
push_up(r);
if(goal == 0)root = r;
}
int Get_kth(int r,int k)
{
push_down(r);
int t = size[ch[r][0]] + 1;
if(t == k)return r;
if(t > k)return Get_kth(ch[r][0],k);
else return Get_kth(ch[r][1],k-t);
}
//在光标后插入长度为len的字符串
void INSERT(int len)
{
Splay(Get_kth(root,pos+1),0);
Splay(Get_kth(root,pos+2),root);
Build(Key_value,0,len-1,ch[root][1]);
push_up(ch[root][1]);
push_up(root);
}
void erase(int r)
{
if(r)
{
s[++tot2] = r;
erase(ch[r][0]);
erase(ch[r][1]);
}
}
void DELETE(int len)
{
Splay(Get_kth(root,pos+1),0);
Splay(Get_kth(root,pos+len+2),root);
erase(Key_value);
pre[Key_value] = 0;
Key_value = 0;
push_up(ch[root][1]);
push_up(root);
}
void Reverse(int len)
{
Splay(Get_kth(root,pos+1),0);
Splay(Get_kth(root,pos+len+2),root);
Update_Rev(Key_value);
push_up(ch[root][1]);
push_up(root);
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n;
int x;
char op[20];
while(scanf("%d",&n) == 1)
{
Init();
while(n--)
{
scanf("%s",&op);
if(op[0] == 'M')
{
scanf("%d",&x);
pos = x;
}
else if(op[0] == 'P')pos--;
else if(op[0] == 'N')pos++;
else if(op[0] == 'I')
{
scanf("%d%*c",&x);
gets(str);
INSERT(x);
}
else if(op[0] == 'D')
{
scanf("%d",&x);
DELETE(x);
}
else if(op[0] == 'R')
{
scanf("%d",&x);
Reverse(x);
}
else if(op[0] == 'G')
{
printf("%c\n",key[Get_kth(root,pos+2)]);
}
}
}
return 0;
}