文藝平衡樹與可持久化文藝平衡樹

FHQ 大法好啊!html

什麼?你說 FHQ 不能維護 LCT ? splay 也不能可持久化啊!node

關於文藝平衡樹:

就是用 FHQtreap 維護區間,reverse 的話就打個標記,裂點的時候釋放,FHQ treap 不會的點這裏ios

其實這裏什麼懶標記也就是相似線段樹的操做吧,要查兒子水錶了就把標記給兒子...git

板子在下面 (毒瘤壓行人 zjq ),看不慣就 Ctrl shift A 嘛函數

傳送門ui

//by Judge
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
const int inf=1e9+7;
const int M=1e5+3;
typedef int arr[M];
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline int read(){ int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(int x,char chr=' '){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]=chr;
} int n,m;
namespace FHQTreap{ arr pos,siz,w,fl; int rt,tot,son[M][2];
    inline int Rand() { static int seed=703; return seed=int(seed*48271LL%(~0u>>1)); }
    inline void pushup(int x){siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;}
    inline int newnode(int x){w[++tot]=x,siz[tot]=1,pos[tot]=Rand();return tot;}
    inline void pushdown(int x){swap(son[x][0],son[x][1]),fl[son[x][0]]^=1,fl[son[x][1]]^=1,fl[x]=0;}
    int merge(int x,int y){ if(!x||!y) return x|y;
        if(pos[x]<pos[y]){if(fl[x]) pushdown(x); son[x][1]=merge(son[x][1],y),pushup(x); return x;}
        if(fl[y]) pushdown(y); son[y][0]=merge(x,son[y][0]),pushup(y); return y;
    }
    void split(int rt,int k,int& x,int& y){
        if(!rt) return x=y=0,void(); if(fl[rt]) pushdown(rt);
        if(siz[son[rt][0]]<k) x=rt,split(son[rt][1],k-siz[son[rt][0]]-1,son[rt][1],y);
        else y=rt,split(son[rt][0],k,x,son[rt][0]); pushup(rt);
    }
    void output(int x){ if(!x) return ; if(fl[x]) pushdown(x);
        output(son[x][0]),print(w[x]),output(son[x][1]);
    }
} using namespace FHQTreap;
int main(){ n=read(),m=read();
    for(int i=1;i<=n;++i)
        rt=merge(rt,newnode(i));
    for(int i=1,l,r,a,b,c;i<=m;++i){
        l=read(),r=read(),split(rt,l-1,a,b);
        split(b,r-l+1,b,c),fl[b]^=1;
        rt=merge(a,merge(b,c));
    } return output(rt),Ot(),0;
}

來個例題(超級毒瘤)spa

NOI2005 維修數列code

mmp 這題真的毒瘤啊!就是一堆操做噁心你,完了讀入操做仍是字符串,煩htm

而後這裏的建樹就是比較騷的了,因爲每次都是直接加一大塊序列,若是一個一個點塞的話可能就掛掉了,那麼咱們能夠用棧來維護建樹過程blog

而後仍是懶標記,不一樣的是這裏有區間賦值的懶標記...

//by Judge
#include<cstdio>
#include<iostream>
using namespace std;
const int inf=1e9+7,M=5e5+3;
inline int Max(int a,int b){return a>b?a:b;}
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline int read(){ int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-'){
        c=getchar(); if(isdigit(c)) f=-1; break;
    } for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} inline int cread(){ char c=getchar(),s[9];
    int x=0; for(;!isupper(c);c=getchar());
    for(;isupper(c)||c=='-';c=getchar()) s[++x]=c;
    if(s[1]=='I') return 1; if(s[1]=='D') return 2;
    if(s[1]=='R') return 4; if(s[1]=='G') return 5;
    if(s[3]=='K') return 3; if(s[3]=='X') return 6;
} char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(int x,char chr='\n'){ if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10); while(sr[++C]=z[Z],--Z);sr[++C]=chr;
} int n,m,op,x,l,r,a,b,c,A[M];
namespace FHQTreap{
    int rt,tot,tail,pool[M],top,stk[M];
    inline int Rand() { static int seed=703; return seed=int(seed*48271LL%(~0u>>1)); }
    struct node{ int val,pos,siz,sum,ls,rs,lmx,rmx,mx,re,co; node(){ls=rs=re=0,co=inf;}
        inline void init(int x){ lmx=rmx=Max(0,x),mx=sum=val=x,siz=1,pos=Rand();}
        inline void cover(int x){co=val=x,sum=x*siz,rmx=lmx=Max(0,sum),mx=Max(sum,x);}
        inline void rever(){swap(ls,rs),swap(lmx,rmx),re^=1;}
    }t[M];
    inline int newnode(int x){ int z=tail?pool[tail--]:++tot;return t[z]=node(),t[z].init(x),z;}
    inline void pushup(int x){ if(!x) return ; t[x].siz=t[t[x].ls].siz+t[t[x].rs].siz+1;
        t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum+t[x].val,t[x].mx=t[t[x].ls].rmx+t[x].val+t[t[x].rs].lmx;
        if(t[x].ls) t[x].mx=Max(t[x].mx,t[t[x].ls].mx); if(t[x].rs) t[x].mx=Max(t[x].mx,t[t[x].rs].mx);
        t[x].lmx=Max(Max(t[t[x].ls].sum+t[x].val+t[t[x].rs].lmx,t[t[x].ls].lmx),0);
        t[x].rmx=Max(Max(t[t[x].rs].sum+t[x].val+t[t[x].ls].rmx,t[t[x].rs].rmx),0);
    }
    inline void pushdown(int x){ if(!x) return ;
        if(t[x].re) t[t[x].ls].rever(),t[t[x].rs].rever(),t[x].re=0;
        if(t[x].co!=inf) t[t[x].ls].cover(t[x].co),t[t[x].rs].cover(t[x].co),t[x].co=inf;
    }
    int merge(int x,int y){ if(!x||!y) return x|y; pushdown(x),pushdown(y);
        if(t[x].pos<t[y].pos) return t[x].rs=merge(t[x].rs,y),pushup(x),x;
        else return t[y].ls=merge(x,t[y].ls),pushup(y),y;
    }
    void split(int rt,int k,int& x,int& y){ if(!rt) return x=y=0,void(); pushdown(rt);
        if(t[t[rt].ls].siz>=k) y=rt,split(t[y].ls,k,x,t[y].ls),pushup(y);
        else x=rt,split(t[x].rs,k-t[t[x].ls].siz-1,t[x].rs,y),pushup(x);
    }
    inline int build(int* A,int n){ int a,b,c;
        top=0,stk[++top]=b=newnode(A[1]);
        for(int i=2;i<=n;++i){ c=newnode(A[i]),a=0;
            while(top&&t[stk[top]].pos>t[c].pos)
                a=stk[top--],pushup(a);
            if(top) t[stk[top]].rs=c;
            t[c].ls=a,stk[++top]=c; if(top==1) b=c;
        } while(top) pushup(stk[top--]); return b;
    }
    inline void insert(){
        l=read(),r=read(),split(rt,l,a,c);
        for(int i=1;i<=r;++i) A[i]=read();
        b=build(A,r),rt=merge(a,merge(b,c));
    }
    inline void delet(int x){
        if(!x) return ; pool[++tail]=x;
        delet(t[x].ls),delet(t[x].rs);
    }
    inline void delet(){ l=read(),r=read();
        split(rt,l-1,a,b),split(b,r,b,c);
        delet(b),rt=merge(a,c);
    }
    inline void cover(){ l=read(),r=read(),x=read();
        split(rt,l-1,a,b),split(b,r,b,c);
        t[b].cover(x),rt=merge(a,merge(b,c));
    }
    inline void rever(){ l=read(),r=read();
        split(rt,l-1,a,b),split(b,r,b,c);
        t[b].rever(),rt=merge(a,merge(b,c));
    }
    inline void q_sum(){ l=read(),r=read();
        split(rt,l-1,a,b),split(b,r,b,c);
        print(t[b].sum),rt=merge(a,merge(b,c));
    }
} using namespace FHQTreap;
int main(){ n=read(),m=read();
    for(int i=1;i<=n;++i) A[i]=read();
    for(rt=build(A,n);m;--m){ op=cread();
        if(op==1) insert();
        else if(op==2) delet();
        else if(op==3) cover();
        else if(op==4) rever();
        else if(op==5) q_sum();
        else if(op==6) print(t[rt].mx);
    } return Ot(),0;
}

關於可持久化文藝平衡樹

Luogu板子題,這玩意兒應該只能 \(FHQ treap\)

(就是好奇爲何空間要開那麼大,我算出來的話是 log 級別的啊...好吧其實也差很少,算上常數的嘛)

整體來說不是很是的 nan ,其實就是江 可持久化線段樹 和 FHQ treap 兩道紫題並在了一塊兒變成了黑題,假的【霧

但可持久化確實大可能是用了可持久化線段樹的思路,考慮新建節點,保留歷史版本什麼的...

因而就這麼愉快的 A 了此題...


聊太多了 QWQ ,開始談題目

首先你得 A 了文藝平衡樹(用 FHQ treap A 的) ,FHQ treap 不會的點這裏

其次你得學會可持久化的思想,可持久化不會的點這裏 (實際上是主席樹?可是想法相似?)

其實別的都是板子,就是 split 的時候比較特殊罷了,還有下穿標記的時候也是,須要新建節點而後連到父節點那裏

//by Judge
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
const int N=2e5;
const int M=(N<<7)+3; //注意看
typedef int arr[M];
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline ll read(){ ll x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} char sr[1<<21],z[20];int C=-1,Z;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
inline void print(ll x,char chr='\n'){
    if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    while(z[++Z]=x%10+48,x/=10);
    while(sr[++C]=z[Z],--Z);sr[++C]=chr;
} int n,op,v,l,r,a,b,c; ll ans;
namespace FHQTreap{ arr rt,pos,siz,fl;
    ll w[M],sum[M]; int now,tot,son[M][2];
    inline int Rand() { static int seed=703;return seed=int(seed*48271LL%(~0u>>1));}
    inline int newnode(ll x=0){return w[++tot]=x,sum[tot]=x,pos[tot]=Rand(),siz[tot]=1,tot;}
    inline int copy(int x){ int y=newnode(); //複製節點最好單獨來一個小函數...而後裏面要 copy 的別忘 copy 全,我被這玩意兒坑了兩次
        son[y][0]=son[x][0],son[y][1]=son[x][1],siz[y]=siz[x];
        w[y]=w[x],sum[y]=sum[x],fl[y]=fl[x]; return y;
    }
    inline void pushup(int x){
        siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;
        sum[x]=sum[son[x][0]]+sum[son[x][1]]+w[x];
    }
    inline void pushdown(int x){ if(!fl[x]) return;  //注意看+1
        if(son[x][0]) son[x][0]=copy(son[x][0]);
        if(son[x][1]) son[x][1]=copy(son[x][1]);
        fl[son[x][0]]^=1,fl[son[x][1]]^=1;
        swap(son[x][0],son[x][1]),fl[x]=0;
    }
    int merge(int x,int y){ if(!x||!y) return x|y; //merge 好像沒什麼特別的
        if(pos[x]<pos[y]) return pushdown(x),son[x][1]=merge(son[x][1],y),pushup(x),x;
        else return pushdown(y),son[y][0]=merge(x,son[y][0]),pushup(y),y;
    }
    void split(int rt,int k,int& x,int& y){ //注意看+1
        if(!rt) return x=y=0,void(); pushdown(rt);
        if(siz[son[rt][0]]>=k) y=copy(rt),split(son[y][0],k,x,son[y][0]),pushup(y); //這裏是copy了以前的節點而後直接拿他作下去了
        else x=copy(rt),split(son[x][1],k-siz[son[x][0]]-1,son[x][1],y),pushup(x);  //同上
    }
} using namespace FHQTreap;
int main(){ //主函數照着題目打就行了
    for(n=read();n;--n){ v=read(),op=read();
        if(op==1){
            l=read()^ans,r=read()^ans,split(rt[v],l,a,b);
            rt[++now]=merge(a,merge(newnode(r),b));
        } else if(op==2){
            l=read()^ans,split(rt[v],l-1,a,b);
            split(b,1,b,c),rt[++now]=merge(a,c);
        } else if(op==3){ l=read()^ans,r=read()^ans;
            split(rt[v],r,a,c),split(a,l-1,a,b);
            fl[b]^=1,rt[++now]=merge(a,merge(b,c));
        } else if(op==4){ l=read()^ans,r=read()^ans;
            split(rt[v],r,a,c),split(a,l-1,a,b);
            print(ans=sum[b]),rt[++now]=merge(a,merge(b,c));
        }
    } return Ot(),0;
}
相關文章
相關標籤/搜索