[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章