1. 程式人生 > >「模板」 FHQ_Treap 區間翻轉

「模板」 FHQ_Treap 區間翻轉

rand for tchar 速度 r+ ++i void clu 回來

「模板」 FHQ_Treap 區間翻轉

<題目鏈接>


沒有旋轉的 Treap 實現區間操作的功能,很好理解,也很好寫,只是速度不算太快。

對於要翻轉的區間,把整棵 Treap(存有區間 \([1,n]\) 的信息)Split 成 \([1,l-1]\)\([l,r]\)\([r+1,n]\) 三部分,給中間部分的根節點打上標記,再一邊下傳標記一邊 Merge 回來。

註意 Split 時,要按元素個數,不能按權值,因為元素個數可以通過維護節點信息的 size 域而直接得到,但隨著區間的翻轉,權值會亂套。

一定註意先推標記!!先推標記!!先推標記!!

就因為標記推晚了,我調了一天。

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
using std::swap;
const int MAXN=100010;
int n,m;
class FHQ_Treap
{
    public:
        FHQ_Treap(void)
        {
            rt=cnt=0;
            memset(a,0,sizeof a);
        }
        void
Insert(int x) { s[++cnt]=node(x,Random(),1); Merge(rt,rt,cnt); } void Reverse(int x,int y) { int l=0,r=0,t=0; Split(rt,x-1,l,t),Split(t,y-x+1,t,r); s[t].lazy^=1,Merge(l,l,t),Merge(rt,l,r); } void
Print(void) { DFS(rt),putchar(\n); } private: bool a[MAXN]; int rt,cnt; struct node { int v,p,size,lazy,c[2]; node(int _v=0,int _p=0,int _size=0) { v=_v,p=_p,size=_size,lazy=0; memset(c,0,sizeof c); } }s[MAXN]; int Random(void) { int x; while(a[x=rand()%MAXN]); a[x]=1; return x; } void Update(int i) { s[i].size=s[s[i].c[0]].size+s[s[i].c[1]].size+1; } void PushDown(int i) { int &l=s[i].c[0],&r=s[i].c[1]; swap(l,r); if(l) s[l].lazy^=1; if(r) s[r].lazy^=1; s[i].lazy=0; } void Split(int i,int x,int &l,int &r) { if(!i) { l=r=0; return; } if(s[i].lazy) PushDown(i); int t=s[s[i].c[0]].size+1; if(x<t) Split(s[r=i].c[0],x,l,s[i].c[0]); else Split(s[l=i].c[1],x-t,s[i].c[1],r); Update(i); } void Merge(int &i,int l,int r) { if(!l || !r) { i=l|r; return; } if(s[l].p>s[r].p) { if(s[l].lazy) PushDown(l); Merge(s[i=l].c[1],s[l].c[1],r); } else { if(s[r].lazy) PushDown(r); Merge(s[i=r].c[0],l,s[r].c[0]); } Update(i); } void DFS(int i) { if(s[i].lazy) PushDown(i); if(s[i].c[0]) DFS(s[i].c[0]); printf("%d ",s[i].v); if(s[i].c[1]) DFS(s[i].c[1]); } }T; int main(int argc,char *argv[]) { srand((unsigned)time(NULL)); scanf("%d %d",&n,&m); for(int i=1;i<=n;++i) T.Insert(i); for(int i=1,l,r;i<=m;++i) { scanf("%d %d",&l,&r); T.Reverse(l,r); } T.Print(); return 0; }

謝謝閱讀。

「模板」 FHQ_Treap 區間翻轉