【可持久化線段樹?!】rope史上最全詳解


https://www.luogu.org/problemnew/show/P3919

看到上面鏈接中的題時,我在學會可持久化線段樹的同時,第一次學會了一個非常屌(cai)的STL大法——rope!!!

這是一個非標准的STL工具,一般情況下要支持c++11或更高才能用(上次去參加APIO時人家毛子評測用的是c++14啊喂!)

 

正題:

它的頭文件是什么:#include<ext/rope> (注:你可以打開devcpp的目錄去翻一翻rope這個頭文件看看它的操作啊!)

 

除了頭文件以外還需要什么:using namespace __gnu_cxx; (注:正是因為需要使用這種非std的標准命名空間,大部分競賽才無法支持這個工具)

 

定義方法:rope<變量類型>變量名稱;

  或       crope 變量名稱;

  其中crope相當於定義成rope<char>,即定義為string類型

 

它到底是什么:

  那得看你想聽哪種解釋了。

  人話解釋:超級string

  算法解釋:塊狀鏈表(即講鏈表與數組的優勢結合,形成分塊思想)

  用途解釋:這本來是一個用於快速操作string的工具,卻一般被定義成int,然后用作可持久化線段樹!

 

它有哪些操作(重點):

  ●如果你把rope定義為string:

    insert(int pos, string &s, int n) 將字符串s的前n位插入rope的下標pos處,如沒有參數n則將字符串s的所有位都插入rope的下標pos處 (補充地址知識:如果你不想從字符串下標為0(即第一個字符)的地址開始取n位,就將你想開始取的地址代入。如s+1表示從字符串下標為1(即第二個字符)的地址開始取n位。int、char等變量類型的數組都適用這種方法來更改數組操作的起始位置。)

  示例代碼:

1 char a[10];
2 for(int i=0;i<10;i++) a[i]=i+'0';
3 r.insert(0,a+1,8);
4 for(int i=0;i<10;i++) cout<<r.at(i);

 

     

      append(string &s,int pos,int n) 把字符串s中從下標pos開始的n個字符連接到rope的結尾,如沒有參數n則把字符串s中下標pos后的所有字符連接到rope的結尾,如沒有參數pos則把整個字符串s連接到rope的結尾(這里已經給你起始位置參數pos了就沒必要用上述的取地址方法了哈)

    (insert和append的區別:insert能把字符串插入到rope中間,但append只能把字符串接到結尾)

 

    substr(int pos, int len) 提取rope的從下標pos開始的len個字符

 

      at(int x) 訪問rope的下標為x的元素

    

    erase(int pos, int num) 從rope的下標pos開始刪除num個字符

 

    copy(int pos, int len, string &s) 從rope的下標pos開始的len個字符用字符串s代替,如果pos后的位數不夠就補足

 

      replace(int pos, string &x);//從rope的下標pos開始替換成字符串x,x的長度為從pos開始替換的位數,如果pos后的位數不夠就補足

 

    以上是常用操作,不常用操作這里就不再贅述。

 

    ●如果你把rope定義為int(這里只是以int為例):

     insert(int pos, int *s, int n) 將int數組(以下的s都是int數組)s的前n位插入rope的下標pos處,如沒有參數n則將數組s的所有位都插入rope的下標pos處

 

    append(int *s,int pos,int n) 把數組s中從下標pos開始的n個數連接到rope的結尾,如沒有參數n則把數組s中下標pos后的所有數連接到rope的結尾,如沒有參數pos則把整個數組s連接到rope的結尾

 

      substr(int pos, int len) 提取rope的從下標pos開始的len個數

 

    at(int x) 訪問rope的下標為x的元素

    

    erase(int pos, int num) 從rope的下標pos開始刪除num個數

 

    copy(int pos, int len, int *s) 從rope的下標pos開始的len個數用數組s代替,如果pos后的位數不夠就補足

 

      replace(int pos, int *x);//從rope的下標pos開始替換成數組x,x的長度為從pos開始替換的位數,如果pos后的位數不夠就補足

  示例代碼:

r.append(3);
r.append(1);
r.append(2);
r.append(1);
r=r.substr(1,3);
for(int i=0;i<r.size();i++) printf("%d ",r.at(i)); 

 

 

它有哪些好處:

  時間復雜度:O(n*sqrt(n)),具體原理詳見塊狀鏈表

  空間復雜度:O(玄學),此處非常神奇,假如用rope存n個整數,它幾乎只需要sqrt(n)的塊空間加上一些鏈表指針的微小空間(個人猜測)。比如下面切的這道題就大方地開了100w個rope,每個rope都是一個存了100w個數的版本……我真是震驚了這東西真的這么省空間?

 

示范切題:以最上面那個鏈接中的題為例(可持久化線段樹模板)

未完待續

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM