天天看點

BZOJ3223: Tyvj 1729 文藝平衡樹(洛谷P3391)Splay

Splay

BZOJ題目傳送門

洛谷題目傳送門

平衡樹維護序列,翻轉區間即相當于交換左右子樹,打個Lazy-Tag就行,感覺比書架簡單。。。

代碼:

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100000
using namespace std;
struct node{
    int to[],fa,size;
}t[N+];
int n,m,nd,rt,id[N+];
bool lazy[N+];
inline char readc(){//讀優
    static char buf[],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,,,stdin);
    if (l==r) return EOF; return *l++;
}
inline int _read(){
    int num=; char ch=readc();
    while (!isdigit(ch)) ch=readc();
    while (isdigit(ch)) num=num*+ch-,ch=readc();
    return num;
}
void pushup(int x){ t[x].size=t[t[x].to[]].size+t[t[x].to[]].size+; }
void pushdown(int x){//下傳标記
    if (!lazy[x]) return;
    int l=t[x].to[],r=t[x].to[];
    swap(t[x].to[],t[x].to[]);//翻轉左右子樹
    lazy[l]^=,lazy[r]^=,lazy[x]=;
}
void rtt(int x,int &w){
    int y=t[x].fa,z=t[y].fa,p=(t[y].to[]!=x);
    if (y==w) w=x;
    else t[z].to[t[z].to[]!=y]=x;
    t[x].fa=z,t[y].fa=x,t[t[x].to[p^]].fa=y;
    t[y].to[p]=t[x].to[p^],t[x].to[p^]=y;
    pushup(y),pushup(x);
}
void splay(int x,int &w){
    while (x!=w){
        int y=t[x].fa,z=t[y].fa;
        if (y!=w)
            if (t[y].to[]==x^t[z].to[]==y) rtt(x,w);
            else rtt(y,w);
        rtt(x,w);
    }
}
void build(int l,int r,int fa){//建樹
    if (l>r) return;
    if (l==r){
        t[id[l]].size=,t[id[l]].fa=fa;
        t[fa].to[l>fa]=id[l]; return;
    }
    int mid=(l+r)>>;
    build(l,mid-,mid),build(mid+,r,mid);
    t[id[mid]].fa=fa,pushup(mid);
    t[fa].to[mid>fa]=id[mid];
}
int srch(int x,int w){//查找第w大的數
    pushdown(x); int p=t[x].to[];
    if (t[p].size+==w) return x;
    if (t[p].size>=w) return srch(p,w);
    return srch(t[x].to[],w-t[p].size-);
}
void nsrt(int l,int r){//翻轉
    int x=srch(rt,l),y=srch(rt,r+);
    splay(x,rt),splay(y,t[x].to[]);//分别把l-1,r+1伸展到根和右子樹
    lazy[t[y].to[]]^=;//l~r這段區間對應的就是y的左子樹
}
int main(){
    n=_read(),m=_read();
    for (int i=;i<=n+;i++) id[i]=++nd;//這道題的初始序列就是1~n。
    build(,n+,),rt=(n+)>>;//這裡要加兩個虛拟節點拿來伸展
    while (m--){
        int l=_read(),r=_read();
        nsrt(l,r);
    }
    for (int i=;i<=n+;i++)
        printf("%d ",srch(rt,i)-);//記得減1
    return printf("\n"),;
}