csu1365 Play with Chain

很显然的splay,第一次用splay操作区间...我实在佩服这个targan大佬,居然搞出这么牛逼的平衡树,调了大概5个小时终于搞定了。。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<string>
#include<set>
#include<algorithm>
#include<vector>
#include<queue>
#include<list>
#include<cmath>
#include<cstring>
#include<map>
#include<stack>
using namespace std;
#define INF 0x3f3f3f3f
#define maxn 300005
#define ull unsigned long long
#define ll long long
#define hashmod 99999839
#define mod 9997
struct tree{//splay树
    int sz[2];//以当前结点为根的左右子树大小,不包括当前结点
    int son[2];//当前结点的左右儿子
    int fa;//当前结点的父亲
    int reverse;//翻转标记
    int v;//当前结点表示的权值
}a[maxn];
int root;//根节点
int len;
int n,m,x,y,z;
bool f;
int isrson(int p,int f){
    return a[f].son[1] == p;
}
void update(int p){//更新p结点的size
    if(a[p].son[0] != -1) a[p].sz[0] = a[a[p].son[0]].sz[0] + a[a[p].son[0]].sz[1] + 1;
    else a[p].sz[0] = 0;
    if(a[p].son[1] != -1) a[p].sz[1] = a[a[p].son[1]].sz[0] + a[a[p].son[1]].sz[1] + 1;
    else a[p].sz[1] = 0;
}
void pushdown(int p){
    swap(a[p].son[0],a[p].son[1]);
    update(p);
    a[p].reverse ^= 1;
    int ls = a[p].son[0],rs = a[p].son[1];
    if(ls != -1) a[ls].reverse ^= 1;
    if(rs != -1) a[rs].reverse ^= 1;
}
int find(int x){//找到序列第x个数对应的结点
    int p = root;
    for(;;){
        if(a[p].reverse) pushdown(p);
        if(a[p].sz[0] >= x) p = a[p].son[0];
        else if(a[p].sz[0] + 1 == x) return p;
        else x = x - a[p].sz[0] - 1,p = a[p].son[1];
    }
}
void changeson(int p,int f,int v){//把p作为f的v儿子,p,f不一定存在
    if(f != -1) a[f].son[v] = p;
    if(p != -1) a[p].fa = f;
    if(f == -1) root = p;
}
void rotate(int p){
    int f = a[p].fa,g = a[f].fa;
    int u = isrson(p,f),v = isrson(f,g);
    changeson(a[p].son[u^1],f,u),changeson(f,p,u^1),changeson(p,g,v);//改变p,f,g的父子关系
    update(f),update(p);
}
void splay(int p,int tar){
    if(a[p].fa == tar) return;
    while(a[a[p].fa].fa != tar && a[p].fa != tar){
        int f = a[p].fa,g = a[f].fa;
        int u = isrson(p,f),v = isrson(f,g);
        if(u ^ v) rotate(p),rotate(p);
        else rotate(f),rotate(p);
    }
    if(a[p].fa != tar) rotate(p);
}
void getsection(int x,int y){//得到[x,y]区间
    splay(find(x - 1),-1),splay(find(y + 1),root);
}
void build(int l,int r){
    len++;
    int p = len;
    int mid = (l + r) >> 1;
    a[p].v = mid,a[p].sz[0] = a[p].sz[1] = 0;
    a[p].son[0] = a[p].son[1] = -1;
    if(l == r) return;
    if(l <= mid - 1) changeson(len + 1,p,0),build(l,mid-1);
    if(mid + 1 <= r) changeson(len + 1,p,1),build(mid+1,r);
    update(p);
}
void flip(int x,int y){
    getsection(x,y);//得到区间[x,y]后打标记
    int p = a[a[root].son[1]].son[0];
    a[p].reverse ^= 1;
}
void cut(int x,int y,int z){//cut [x,y] z 把区间x,y剪切到z位置后
    //先得到区间[x,y],将其x-1rotate到根,将y+1rotate到根的儿子,则y+1结点的左儿子为根的树即为该区间
    getsection(x,y);
    int p = a[a[root].son[1]].son[0];
    a[a[p].fa].son[0] = -1;
    update(a[p].fa),update(root);
    int t = p;
    p = find(z);
    splay(p,-1),p = find(z + 1),splay(p,root);
    p = a[root].son[1],a[p].son[0] = t,a[t].fa = p;
    update(p),update(root);
}
void print(int p){
    if(p == -1) return;
    if(a[p].reverse) pushdown(p),update(p);
    print(a[p].son[0]);
    if(a[p].v != 0 && a[p].v != n + 1)
        if(!f) printf("%d",a[p].v),f = true;
        else printf(" %d",a[p].v);
    print(a[p].son[1]);
}
int main(){
    freopen("a.in","r",stdin);
    freopen("b.out","w",stdout);
    char op[10];
    while(~scanf("%d%d",&n,&m)){
        if(n < 0 && m < 0) break;
        len = 0,root = 1,f = false;
        build(0,n+1);
        a[root].fa = -1;
        for(int i = 1;i <= m;++i){
            scanf("%s",op);
            if(op[0] == 'C'){
                scanf("%d%d%d",&x,&y,&z);
                ++x,++y,++z;
                cut(x,y,z);
                continue;
            }
            scanf("%d%d",&x,&y);
            ++x,++y;
            flip(x,y);
        }
        print(root),putchar('\n');
    }
    return 0;
}

 

posted @ 2018-08-18 15:55  zhuiyicc  阅读(100)  评论(0编辑  收藏  举报