stl学习(三)crope的用法

转载自http://blog.csdn.net/iamzky/article/details/38348653

曾经我不会写平衡树……于是在STL中乱翻……学到了pb_ds库中的SXBK的斐波那契堆、支持kth的set,和……ext/rope

先发一个官方的 说明 (鸣谢maoxiaohan1999):

http://www.sgi.com/tech/stl/Rope.html

再来例题

IOI2012

scrivener

题意

设计支持如下 3 种操作: 
1.T x:在文章末尾打下一个小写字母 x。(type 操作) 
2.U x:撤销最后的x 次修改操作。(Undo 操作) 
(注意Query 操作并不算修改操作) 
3.Q x:询问当前文章中第x 个字母并输出。(Query 操作)

操作数n<=100000 在线算法

clj都说这是道rope傻逼题……

我的rope标程:

 

    #include<cstdio>  
    #include<cstring>  
    #include<cctype>  
    #include<iostream>  
    #include<algorithm>  
    #include<ext/rope>  
    using namespace std;  
    using namespace __gnu_cxx;  
    const int maxn=1e5+10;  
    rope<char> *his[maxn];  
    int n;  
    int d[maxn];  
    inline int lowbit(int x){  
        return x&-x;  
    }  
    inline void updata(int x){  
        while(x<=n){  
            d[x]++;  
            x+=lowbit(x);  
        }  
    }  
    inline int get(int x){  
        int res=0;  
        while(x){  
            res+=d[x];  
            x-=lowbit(x);  
        }return res;  
    }  
    inline char getC(){  
        char ch=getchar();  
        while(!isalpha(ch))ch=getchar();  
        return ch;  
    }  
    inline int getint(){  
        int res=0;  
        char ch,ok=0;  
        while(ch=getchar()){  
            if(isdigit(ch)){  
                res*=10;res+=ch-'0';ok=1;  
            }else if(ok)break;  
        }return res;  
    }  
    void deb(rope<char> s){  
        for(int i=0;i<s.length();i++)  
        cout<<s[i];puts("");  
    }  
    int main(){  
        freopen("type.in","r",stdin);  
        freopen("type.out","w",stdout);  
        n=getint();  
        his[0]=new rope<char>();  
        for(int i=1;i<=n;i++){  
            his[i]=new rope<char>(*his[i-1]);  
    //      deb(*his[i]);  
            char opt=getC();  
            if(opt=='T'){  
                char x=getC();  
                his[i]->push_back(x);  
                updata(i);  
            }else  
            if(opt=='U'){  
                updata(i);  
                int x=getint();  
                int l=1,r=i,mid,now=get(i);  
                while(l<r){  
                    mid=(l+r)>>1;  
                    if(now-get(mid)>x)  
                        l=mid+1;  
                    else  
                        r=mid;  
                }  
                his[i]=his[l-1];  
                  
            }else  
            if(opt=='Q'){  
                int x=getint()-1;  
                putchar(his[i]->at(x));  
                putchar('\n');    
            }  
    //      deb(*his[i]);  
        }  
        return 0;  
    }  

 

可持久化在哪里呢?

 

    his[i]=new rope<char>(*his[i-1]);  

 

 

就是这一句!它可以实现O(1)的拷贝历史版本,由于rope的底层是平衡树,copy时copy根节点就行了

用它就可以轻松实现可持久化数组

其余操作不用多说

例二

AHOI2006文本编辑器editor

题意

设计数据结构支持

插入删除反转字符串

    #include <cstdio>  
    #include <ext/rope>  
    #include <iostream>  
    #include <algorithm>  
    using namespace std;  
    using namespace __gnu_cxx;  
    crope a,b,tmp;  
    char s[10];  
    int now,n,len,size;  
    char str[2000000],rstr[2000000];  
    int main(){  
        scanf("%d",&n);  
        while(n--){  
            scanf("%s",s);  
            switch(s[0]){  
                case 'M':{scanf("%d",&now);break;}  
                case 'P':{now--;break;}  
                case 'N':{now++;break;}  
                case 'G':{putchar(a[now]);putchar('\n');break;}  
                case 'I':{  
                    scanf("%d",&size);  
                    len=a.length();  
                    for(int i=0;i<size;i++){  
                        do{str[i]=getchar();}  
                        while(str[i]=='\n');  
                        rstr[size-i-1]=str[i];  
                    }  
                    rstr[size]=str[size]='\0';  
                    a.insert(now,str);  
                    b.insert(len-now,rstr);  
                    break;  
                }  
                case 'D':{  
                    scanf("%d",&size);  
                    len=a.length();  
                    a.erase(now,size);  
                    b.erase(len-now-size,size);  
                    break;  
                }  
                case 'R':{  
                    scanf("%d",&size);  
                    len=a.length();  
                    tmp=a.substr(now,size);  
                    a=a.substr(0,now)+b.substr(len-now-size,size)+a.substr(now+size,len-now-size);  
                    b=b.substr(0,len-now-size)+tmp+b.substr(len-now,now);                 
                    break;  
                }  
            }         
        }  
        return 0;  
    }  

由于rope的底层实现,insert,erase,get都是logn的

就是翻转不行,不是自己手写的打不了标记啊!!

怎么办?

答:同时维护一正一反两个rope……反转即交换两个子串……Orz……

区间循环位移?简单,拆成多个子串连起来就好了……

区间a变b b变c c变d …… z变a? 呃……维护26个rope?

区间和?滚蛋,那是线段树的活

区间kth?sorry,与数值有关的操作rope一概不支持……

5555 维修数列只能自己写了……

最后的Hint: 

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个元素


友情提示:cena不支持rope



posted @ 2016-10-13 19:06  keshuqi  阅读(644)  评论(0编辑  收藏  举报