stl学习(三)crope的用法

来源:互联网 发布:淘宝请人代付退款 编辑:程序博客网 时间:2024/05/17 01:19

转载自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)在末尾添加xinsert(pos,x)在pos插入xerase(pos,x)从pos开始删除x个replace(pos,x)从pos开始换成xsubstr(pos,x)提取pos开始x个at(x)/[x]访问第x个元素

友情提示:cena不支持rope



1 0
原创粉丝点击