题目描述:https://www.luogu.org/problemnew/show/P3391

 

解析:在这里主要讲一下对splay上点的权值的看法。首先,我们发现一颗splay的中序遍历始终是不变的,所以想到用splay的中序遍历来表示原数组的位置。那么怎么实现呢?我们只需要刚开始建树的时候以位置为权值来建树。换一种说法,以位置建树只是为了让splay的中序遍历有序。所以事实上,这颗splay任然是以原数组的数为权值的,只不过是刚开始建树的时候换了一个建树方式。那么有同学可能会问,swap过后不就不满足splay左小右大的性质了吗?肯定不满足啊。有同学可能会问另外一个问题,怎么保证r+1一定能旋转到l-1的右儿子去呢,不是已经不满足splay的性质了吗?注意,splay的旋转操作是跟点的权值没有关系的,它只是跟splay怎么建的树有关系。

    附上代码(origin为原数组):

#include<cstdio>
#include<algorithm>
using namespace std;

const int MAXN=100005;
int n,m;
int root;
struct Node{
    int size,son[2],val,fa,tag;
}node[MAXN];
int ndnum=0;
int origin[MAXN];

int check(int x){
    return x==node[node[x].fa].son[1];
}

void update(int x){
    node[x].size=node[node[x].son[0]].size+node[node[x].son[1]].size+1;
}

void rotate(int x){
    int y=node[x].fa,z=node[y].fa,d=check(x),xx=node[x].son[d^1];
    node[y].son[d]=xx;node[xx].fa=y;
    node[z].son[check(y)]=x;node[x].fa=z;
    node[x].son[d^1]=y;node[y].fa=x;
    update(y);update(x);
} 

void splay(int x,int to=0){
    while(node[x].fa!=to){
        int y=node[x].fa,z=node[y].fa;
        if(z!=to){
            if(check(x)==check(y)) rotate(y);
            else rotate(x);
        }    
        rotate(x);
    }
    if(!to) root=x;
}

void insert(int x){
    int cur=root,f=0;
    while(cur&&node[cur].val!=x){
        f=cur;
        cur=node[cur].son[x>node[cur].val];
    }
    cur=++ndnum;
    if(f) node[f].son[x>node[f].val]=cur;
    node[cur].size=1;node[cur].tag=0;
    node[cur].son[0]=node[cur].son[1]=0;
    node[cur].val=x;node[cur].fa=f;
    splay(cur);
}

void pushdown(int cur){
    if(node[cur].tag){
        node[node[cur].son[0]].tag^=1;
        node[node[cur].son[1]].tag^=1;
        node[cur].tag=0;
        swap(node[cur].son[0],node[cur].son[1]);
    }
}

int kth(int k){
    int cur=root;
    while(1){
        pushdown(cur);
        if(k<=node[node[cur].son[0]].size)
        cur=node[cur].son[0];
        else{
            k-=node[node[cur].son[0]].size+1;
            if(!k) return cur;
            cur=node[cur].son[1];
        } 
    }
} 

void reserve(int l,int r){
    l=kth(l-1);r=kth(r+1);
    splay(l);splay(r,l);
    node[node[node[root].son[1]].son[0]].tag^=1;
}

void write(int cur){
    pushdown(cur);
    if(node[cur].son[0]) write(node[cur].son[0]);
    if(node[cur].val>1&&node[cur].val<n+2) printf("%d ",origin[node[cur].val-1]);
    if(node[cur].son[1]) write(node[cur].son[1]);
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&origin[i]); 
    for(int i=1;i<=n+2;i++) insert(i);
    for(int i=1;i<=m;i++){
        int l,r;
        scanf("%d%d",&l,&r);
        reserve(l+1,r+1);
    }
    write(root);
    return 0;
}
View Code