【Luogu】P3391文艺平衡树(Splay)

  题目链接

  ddosvoid和自为风月马前卒教了我这道题

  他们好强啊

  如果我们要反转区间[l,r]

  我们首先把l的前驱旋转到根节点

  再把r的后继旋转到根节点的右儿子

  那么此时根节点的右儿子的左儿子所代表的就是区间l,r

  具体为啥不知道

  然后可以给splay的节点打标记,就像线段树一样

inline void pushdown(int x){
    if(!tree[x].tag)    return;
    swap(tree[x].e[0],tree[x].e[1]);
    tree[tree[x].e[0]].tag^=1;
    tree[tree[x].e[1]].tag^=1;
    tree[x].tag=0;
}

  这就是标记下传

  

#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
using std::swap;

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int root;int n;int m;

struct Splay{
    struct node{
        int e[2],size,fa;
        bool tag;
    }tree[200000];
    inline int iden(int x){    return x==tree[tree[x].fa].e[1];    }
    inline void update(int x){    tree[x].size=tree[tree[x].e[0]].size+tree[tree[x].e[1]].size+1;    }
    inline void connect(int x,int fa,int how){    tree[x].fa=fa;    tree[fa].e[how]=x;    }
    void rotate(int x){
        int y=tree[x].fa;    if(y==root)    root=x;
        int r=tree[y].fa;
        //pushdown(r);    pushdown(y);    pushdown(x);
        int sony=iden(x);    int sonr=iden(y);
        int b=tree[x].e[sony^1];
        connect(b,y,sony);
        connect(y,x,sony^1);
        connect(x,r,sonr);
        update(y);    update(x);
    }
    inline void pushdown(int x){
        if(!tree[x].tag)    return;
        swap(tree[x].e[0],tree[x].e[1]);
        tree[tree[x].e[0]].tag^=1;
        tree[tree[x].e[1]].tag^=1;
        tree[x].tag=0;
    }
    void splay(int pos,int to){
        while(tree[pos].fa!=to){
            if(tree[tree[pos].fa].fa==to)    rotate(pos);
            else
                if(iden(pos)==iden(tree[pos].fa)){    rotate(tree[pos].fa);    rotate(pos);    }
                else    {    rotate(pos);    rotate(pos);    }
        }
        update(pos);
    }
    int build(int l,int r){
        if(l>r)    return 0;
        int mid=(l+r)>>1;
        int lson=build(l,mid-1);
        connect(lson,mid,0);
        int rson=build(mid+1,r);
        connect(rson,mid,1);
        tree[mid].tag=0;
        update(mid);
        return mid;
    }
    int find(int val){
        int now=root;val--;
        pushdown(now);
        while(val!=tree[tree[now].e[0]].size){
            if(tree[tree[now].e[0]].size<val){
                val-=tree[tree[now].e[0]].size+1;
                now=tree[now].e[1];
            }
            else    now=tree[now].e[0];
            pushdown(now);
        }
        return now;
    }
    void print(int now){
        if(!now)    return;
        pushdown(now);
        print(tree[now].e[0]);
        if(now!=1&&now!=n+2)    printf("%d ",now-1);
        print(tree[now].e[1]);
    }
}s;


int main(){
    n=read();    m=read();    root=s.build(1,n+2);
    while(m--){
        int l=read(),r=read();
        int x=s.find(l);    s.splay(x,0);
        int y=s.find(r+2);    s.splay(y,root);
        s.tree[s.tree[y].e[0]].tag^=1;
    }
    s.print(root);
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/7940467.html