文艺平衡树 lg3391(splay维护区间入门)

splay是支持区间操作的,先做这道题入个门

大多数操作都和普通splay一样,就不多解释了,只解释一下不大一样的操作

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
inline int read(){
    int w=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        w=(w<<3)+(w<<1)+ch-48;
        ch=getchar(); 
    }
    return w*f;
}
int n,m,tot,cnt,root;
struct node{
    int ch[2],sum,cnt,val,f,rev;//比普通平衡树多一个lazy tag
}st[1000010];
inline void push_up(int p){
    st[p].sum=st[st[p].ch[0]].sum+st[st[p].ch[1]].sum+st[p].cnt;
}
inline bool identify(int p){
    return st[st[p].f].ch[1]==p;
}
inline void connect(int x,int fa,int son){
    st[x].f=fa;st[fa].ch[son]=x;return;
}
inline void rotate(int x){
    int y=st[x].f;int z=st[y].f;
    int yson=identify(x);int zson=identify(y);
    int b=st[x].ch[yson^1];
    connect(b,y,yson);connect(y,x,(yson^1));connect(x,z,zson);
    push_up(y);push_up(x);return;
}
inline void splay(int x,int goal){
    while(st[x].f!=goal){
        int y=st[x].f;int z=st[y].f;
        int yson=identify(x);int zson=identify(y);
        if(z!=goal){
            if(yson==zson) rotate(y);
            else rotate(x);
        }
        rotate(x);
    }
    if(!goal) root=x;
    return;
}
inline void insert(int x){
    int now=root;int f=0;
    while(st[now].val!=x&&now){
        f=now;
        now=st[now].ch[x>st[now].val];
    }
    if(now){
        st[now].cnt++;
    }
    else{
        tot++;now=tot;
        if(f){
            st[f].ch[x>st[f].val]=now;
        }
        st[now].ch[0]=st[now].ch[1]=0;
        st[now].cnt=st[now].sum=1;
        st[now].val=x;st[now].f=f;
    }
    splay(now,0);return;
}
inline void push_down(int p){
    int ls=st[p].ch[0];int rs=st[p].ch[1];
    if(st[p].rev){
        swap(st[p].ch[0],st[p].ch[1]);
        st[st[p].ch[0]].rev^=1;
        st[st[p].ch[1]].rev^=1;
        st[p].rev=0;
    }
}
inline void find(int x){
    int now=root;if(!now) return;
    while(st[now].val!=x&&st[now].ch[x>st[now].val]){
        now=st[now].ch[x>st[now].val];
    }
    splay(now,0);return;
}
inline int Next(int x,int f){
    find(x);int now=root;
    if(st[now].val<x&&!x) return now;
    if(st[now].val>x&&x) return now;
    now=st[now].ch[f];
    while(st[now].ch[f^1]) now=st[now].ch[f^1];
    return now;
}
inline int k_th(int x){
    int now=root;
    if(st[now].sum<x) return false;
    while(true){
        push_down(now);//在查找的时候记得下移标记
        int ls=st[now].ch[0];
        if(x>st[ls].sum+st[now].cnt){
            x-=st[ls].sum+st[now].cnt;
            now=st[now].ch[1];
        }
        else if(x<=st[ls].sum){
            now=ls;
        }
        else return now;//这个地方把返回原值改成返回位置
    }
}inline void rev(int l,int r){
    int x=k_th(l-1);int y=k_th(r+1);
    splay(x,0);splay(y,x);
    st[st[y].ch[0]].rev^=1;
}//翻转的操作就是将l-1转到根上,r+1转到根的右儿子,然后l到r这个区间就是根右儿子的左儿子(比较绕,可以画个图想一想
inline void output(int p){
    push_down(p);
    if(st[p].ch[0]) output(st[p].ch[0]);
    if(st[p].val>=1&&st[p].val<=n) printf("%d ",st[p].val);
    if(st[p].ch[1]) output(st[p].ch[1]);
}//输出的时候下推一下标记,输出顺序就是二叉树的顺序
int main(){
    n=read();m=read();int i,j,k;
    insert(INF);insert(-INF);
    for(i=1;i<=n;i++){
        insert(i);
    }
    while(m--){
        int x,y;x=read();y=read();
        rev(x+1,y+1);
    }
    output(root);
    return 0;
}
posted @ 2018-12-15 10:18  温词  阅读(177)  评论(0编辑  收藏  举报