zoukankan      html  css  js  c++  java
  • 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('
    ');    
                }  
        //      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('
    ');break;}  
                    case 'I':{  
                        scanf("%d",&size);  
                        len=a.length();  
                        for(int i=0;i<size;i++){  
                            do{str[i]=getchar();}  
                            while(str[i]=='
    ');  
                            rstr[size-i-1]=str[i];  
                        }  
                        rstr[size]=str[size]='';  
                        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



  • 相关阅读:
    四种会话跟踪技术的对比
    【转载】.NET中使用Redis
    【转载】Windows平台下利用APM来做负载均衡方案
    【转载】Windows平台分布式架构实践
    MVC插件式开发平台
    如何用JS和HTML 做一个桌面炒股小插件【原创】
    如果用HTML5做一个在线视频聊天【原创】
    BraveOS正式版发布,希望大家下载使用
    短期将不再更新更多内容,见谅!
    打造自己的移动绿色版 Python 环境
  • 原文地址:https://www.cnblogs.com/keshuqi/p/5957685.html
Copyright © 2011-2022 走看看