[STL] 浅谈Rope使用(附[BZOJ]1507 Editor)

前言

今天做一道题:BZOJ1507: [NOI2003]Editor,然后用splay打了一个,真的心累。然后看网上的做法,竟然有人用不到40行的代码A掉了这题,然后一看,就是今天要谈的Rope。

简介

在2008年OI集训论文上有介绍《对块状链表的一点研究》,块状链表主要是结合了链表和数组各自的优点,链表中的节点指向每个数据块,即数组,并且记录数据的个数,然后分块查找和插入。在g++头文件中,ext/rope中有成型的块状链表,在using namespace __gnu_cxx;空间中,使用起来是比较的方便的。
其实可以把它认为是可持久化平衡树吧。

基本操作

#include <cstdio>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;
//要用的头文件和命名空间等
rope test;//定义
test.push_back(x);//在末尾添加x
test.insert(pos,x);//在pos插入x  
test.erase(pos,x);//从pos开始删除x个
test.copy(pos,len,x);//从pos开始到pos+len为止用x代替
test.replace(pos,x);//从pos开始换成x
test.substr(pos,x);//提取pos开始x个
test.at(x)/[x];//访问第x个元素

其算法复杂度n(n) ,可以在很短的时间内实现快速的插入、删除和查找字符串,真是太牛了。
英文版详解:http://www.sgi.com/tech/stl/Rope.html

注意

对于这种STL,NOI系列考试尽量不要尝试(没人试过是否能用),一般校内考试等用lemon等测评的考试还是行的。

例题 [NOI2003] 文本编辑器

【问题描述】

这里写图片描述

【输入文件】

输入文件的第一行是指令条数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

题解

如果你看懂了题目,懂得用Rope的话,直接秒掉。

代码

#include <cstdio>
#include <cstring>
#include <ext/rope>
using namespace std;
using namespace __gnu_cxx;

const int size = 3000000+10;
crope list;
int t,now,x;
char s[10];
char ch[size];

int main() {
    scanf("%d",&t);
    while(t--) {
        scanf("%s",s);
        switch(s[0]) {
        case 'M':scanf("%d",&now);break;
        case 'P':now--;break;
        case 'N':now++;break;
        case 'I':
            scanf("%d",&x);
            for(int i=0;i<x;i++) {
                ch[i]=getchar();while(ch[i]=='\n') ch[i]=getchar();
            }
            ch[x]=0;list.insert(now,ch);
            break;
        case 'D': scanf("%d",&x);;list.erase(now,x);break;
        case 'G': scanf("%d",&x);;list.copy(now,x,ch);ch[x]=0;puts(ch);
        }
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章