HNOI2017 spaly题解

终于调过了,决定把这份巨屎无比的冗长代码贴上来
解题思路:
主要在于发现两个题目的性质:
1.对于插入操作,插入的元素只可能作为他前驱的右儿子或者后继的左儿子
2.旋转最大最小值,并不会改变树的结构,实质上就是把要删除的那个元素直接提到根节点(模拟即可证明)

有了这两条性质,我们可以发现只需要维护这棵树的形态并能够在log内的复杂度求树上某个点的深度
于是我们就可以想到用LCT(有删除操作)。
恰好LCT又是以深度为key值建树,所以我们只需要再维护原树的父子关系,便于LCT的link-cut,这个可以用set维护(找前驱后继),然后每次相当于询问每个点到根节点的距离,又变成模板了

代码细节很多,还要注意这是一棵有根树,还要维护根节点是谁
代码:

#include
#define ll long long
#define mm(a, b) memset(a, b, sizeof(a))
#define For(i, a, b) for(int i = (a);i <= (b); ++i)
#define rep(i, a, b) for(int i = (a);i >= (b); --i)
#define gnn cerr << "GNN睡着了" << endl;

using namespace std;

const int inf = 1e9 + 1;

int read(){
    int sum = 0, fg = 1;
    char c = getchar();

    while(c < '0' || c > '9'){if(c == '-')fg = -1;c = getchar();}
    while(c >='0' && c <='9')sum = (sum << 1) + (sum << 3) + c-'0', c = getchar();

    return sum * fg;
}

const int maxn = 200010;

void file(){
#ifndef ONLINE_JUDGE
    freopen("ai.in", "r", stdin);
    freopen("ai.out", "w", stdout);
#endif
}

map<int , int> q;

int m, tree[maxn], val[maxn], ch[maxn][2], rev[maxn], cnt, fa[maxn];

bool isroot(int h){return ch[fa[h]][0] != h && ch[fa[h]][1] != h;}

void pushup(int h){tree[h] = 1; tree[h] +=  tree[ch[h][0]] + tree[ch[h][1]];}

void pushdown(int h){
    if(!rev[h]) return;

    rev[h] = 0;
    swap(ch[h][0], ch[h][1]);

    if(ch[h][0]) rev[ch[h][0]] ^= 1;
    if(ch[h][1]) rev[ch[h][1]] ^= 1;
}

void PUSHDOWN(int h){
    if(!isroot(h)) PUSHDOWN(fa[h]);
    pushdown(h);
}

void rotate(int h){
    int father = fa[h], grandfa = fa[father];
    bool w = (ch[father][1] == h);

    fa[ch[h][w^1]] = father;
    ch[father][w] = ch[h][w^1];

    fa[father] = h;
    ch[h][w^1] = father;

    fa[h] = grandfa;
    if(ch[grandfa][0] == father) ch[grandfa][0] = h;
    else if(ch[grandfa][1] == father) ch[grandfa][1] = h;

    pushup(father), pushup(h);
}

bool pd(int h){return ch[fa[h]][0] == h;}

void splay(int h){
    PUSHDOWN(h);

    while(!isroot(h)){
        if(!isroot(fa[h]) && pd(h) == pd(fa[h])) rotate(fa[h]);
        rotate(h);
    }
}

void access(int h){

    int y = 0;
    while(h){
        splay(h);
        ch[h][1] = y;
        pushup(h);

        y = h;
        h = fa[h];
    }
}

void makeroot(int h){

    access(h);
    splay(h);

    rev[h] ^= 1;
}

void cut(int x,int y){

    makeroot(x);
    access(y);
    splay(y);

    fa[x] = ch[y][0] = 0;
}

void link(int x,int y){
    makeroot(x);
    fa[x] = y;
}

void Get(){
    m = read();
}

int zf = 0, nowroot, truelyfa[maxn], truelych[maxn][2];

int get_dep(int h){

    makeroot(nowroot);
    access(h);
    splay(h);

    return tree[h];
}

set<int> Set;
set<int>::iterator it, other;

int nowyuansu, flag = 0;

void _Min(int type){
    it = Set.begin();
    int Min = *it;

    int id = q[Min];
    printf("%d\n", get_dep(id));

    if(type == 1) nowyuansu = Min;

    if(id == nowroot) {flag = 1; return;}
    if(truelych[id][1]) cut(truelych[id][1], id);
    if(truelyfa[id]){
        cut(truelyfa[id], id);
        int father = truelyfa[id];
        truelych[father][0] = truelych[id][1];
        if(truelych[id][1]){
            truelyfa[truelych[id][1]] = father;
            link(truelych[id][1], father);
        }
    }

    truelyfa[id] = 0;
    if(nowroot == id){
        if(truelych[id][1]){
            link(id, truelych[id][1]);
            truelyfa[truelych[id][1]] = id;
        }
    }
    else{
        truelych[id][1] = nowroot;
        truelyfa[nowroot] = id;

        link(id, nowroot);
    }

    nowroot = id;
    makeroot(nowroot);
}

void _Max(int type){
    it = Set.end();
    -- it;
    int Max = *it;

    int id = q[Max];
    printf("%d\n", get_dep(id));

    if(type == 1) nowyuansu = Max;

    if(id == nowroot) {flag = 1; return;}
    if(truelych[id][0]) cut(truelych[id][0], id);
    if(truelyfa[id]){
        cut(truelyfa[id], id);
        int father = truelyfa[id];
        truelych[father][1] = truelych[id][0];
        if(truelych[id][0]){
            truelyfa[truelych[id][0]] = father;
            link(truelych[id][0], father);
        }
    }

    truelyfa[id] = 0;
    if(nowroot == id){
        if(truelych[id][0]){
            link(id, truelych[id][0]);
            truelyfa[truelych[id][0]] = id;
        }
    }
    else{
        truelych[id][0] = nowroot;
        truelyfa[nowroot] = id;

        link(id, nowroot);
    }

    nowroot = id;
    makeroot(nowroot);
}

void solve(){
    while(m --){
        int type = read();

        if(type == 1){

            int x = read();
            ++ cnt;
            q[x] = cnt;

            zf ++;
            if(zf == 1) nowroot = cnt;

            int pre = inf;

            it = Set.lower_bound(x);
            if(it != Set.begin()) --it, pre = *it;
            other = Set.upper_bound(x);

            int suf = inf;
            if(other != Set.end()) suf = *other;

            Set.insert(x);

            int ans = 1;

            if(pre != inf && suf != inf){
                int ans1 = get_dep(q[pre]), ans2 = get_dep(q[suf]);
                makeroot(nowroot);

                if(get_dep(q[pre]) < get_dep(q[suf])){
                    fa[cnt] = q[suf];

                    truelyfa[cnt] = q[suf];
                    truelych[q[suf]][0] = cnt;

                    ans = ans2 + 1;
                }
                else{
                    fa[cnt] = q[pre];

                    truelyfa[cnt] = q[pre];
                    truelych[q[pre]][1] = cnt;

                    ans = ans1 + 1;
                }
            }
            else if(pre != inf){
                int ans1 = get_dep(q[pre]);

                makeroot(nowroot);
                fa[cnt] = q[pre];

                truelyfa[cnt] = q[pre];
                truelych[q[pre]][1] = cnt;

                ans = ans1 + 1;
            }
            else if(suf != inf){
                int ans2 = get_dep(q[suf]);

                makeroot(nowroot);
                fa[cnt] = q[suf];

                truelyfa[cnt] = q[suf];
                truelych[q[suf]][0] = cnt;

                ans = ans2 + 1;
            }

            printf("%d\n", ans);
        }

        else if(type == 2){
            _Min(0);
        }

        else if(type == 3){
            _Max(0);
        }

        else if(type == 4){
            flag = 0;
            _Min(1);
            if(flag && zf != 1){
                cut(nowroot, truelych[nowroot][1]);
                truelyfa[truelych[nowroot][1]] = 0;
                nowroot = truelych[nowroot][1];
            }
            else if(zf != 1){
                cut(nowroot, truelych[nowroot][1]);
                nowroot = truelych[nowroot][1];
                truelyfa[nowroot] = 0;
            }
            -- zf;

            makeroot(nowroot);
            Set.erase(nowyuansu);
        }
        else{
            flag = 0;
            _Max(1);
            if(flag && zf != 1){
                cut(nowroot, truelych[nowroot][0]);
                truelyfa[truelych[nowroot][0]] = 0;
                nowroot = truelych[nowroot][0];
            }
            else if(zf != 1){
                cut(nowroot, truelych[nowroot][0]);
                nowroot = truelych[nowroot][0];
                truelyfa[nowroot] = 0;
            }
            --zf;

            makeroot(nowroot);
            Set.erase(nowyuansu);
        }

    }
}

int main(){

    file();
    Get();
    solve();

    return 0;
}

你可能感兴趣的:(数据结构)