[HNOI2017]单旋(LCT)

Description

维护一棵spaly(单旋splay),要求你支持以下五种操作:

  1. 插入节点
  2. 单旋删除最小值
  3. 单旋删除最大值
  4. 单旋最小值到根
  5. 单旋最大值到根

其中每个操作的代价为所影响节点的深度。

Solution

完整题面自己看吧,这里只有一个简要的……

考虑单旋(删除)最小(大)值,经过手玩可以发现,其实只是把最小(大)值与它的父亲断开,然后与当前根节点相连,且根节点是它的右(左)儿子。

至于插入操作,不难发现插入节点不是其前驱的右儿子,就是其后继的左儿子。所以记录每个节点的左右儿子,然后用 set s e t 查找即可。

整棵树的操作用 LCT L C T 维护即可。

#include 
using namespace std;

const int maxn = 100005;
int m;

inline int gi()
{
    char c = getchar();
    while (c < '0' || c > '9') c = getchar();
    int sum = 0;
    while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
    return sum;
}

int root, f[maxn], ch[maxn][2], siz[maxn], rev[maxn];

#define isroot(x) (ch[f[x]][0] != x && ch[f[x]][1] != x)
#define get(x) (ch[f[x]][1] == x)
#define update(x) siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1

inline void rotate(int x)
{
    int fa = f[x], gfa = f[fa], k = get(x);
    if (!isroot(fa)) ch[gfa][get(fa)] = x;
    ch[fa][k] = ch[x][k ^ 1]; f[ch[x][k ^ 1]] = fa;
    ch[x][k ^ 1] = fa; f[fa] = x;
    f[x] = gfa;
    update(fa); update(x);
}

inline void pushdown(int x)
{
    if (!x || !rev[x]) return ;
    if (ch[x][0]) rev[ch[x][0]] ^= 1;
    if (ch[x][1]) rev[ch[x][1]] ^= 1;
    rev[x] ^= 1;
    swap(ch[x][0], ch[x][1]);
}

int stk[maxn], top;
inline void splay(int x)
{
    stk[top = 1] = x;
    while (!isroot(x)) stk[++top] = x = f[x];
    while (top) pushdown(stk[top--]);
    x = stk[1];
    while (!isroot(x)) {
        int fa = f[x];
        if (!isroot(fa)) get(x) ^ get(fa) ? rotate(x) : rotate(fa);
        rotate(x);
    }
}

inline void access(int x)
{
    for (int y = 0; x; y = x, x = f[x])
        splay(x), ch[x][1] = y, update(x);
}

inline void make_root(int x) {access(x); splay(x); rev[x] ^= 1;}
inline void link(int x, int y) {make_root(x); f[x] = y; update(y);}
inline void cut(int x, int y) {make_root(x); access(y); splay(y); f[x] = ch[y][0] = 0;}

set<int> S;
map<int, int> M;
int fa[maxn], ls[maxn], rs[maxn], tot;

void insert(int x)
{
    M[x] = ++tot;
    if (S.empty()) {
        S.insert(x); root = tot;
        puts("1"); return;
    }
    set<int>::iterator p = S.upper_bound(x);
    int k;
    if ((p == S.end()) || ls[k = M[*p]]) {
        int k = M[*(--p)];
        link(tot, k); rs[k] = tot; fa[tot] = k;
    } else {
        int k = M[*p];
        link(tot, k); ls[k] = tot; fa[tot] = k;
    }
    S.insert(x);
    make_root(root); access(tot); splay(tot);
    printf("%d\n", siz[tot]);
}

inline void splay_min()
{
    int x = M[*S.begin()];
    if (root == x) {puts("1"); return;}
    make_root(root); access(x); splay(x);
    printf("%d\n", siz[x]);
    cut(x, fa[x]);
    link(x, root);
    if (rs[x]) cut(x, rs[x]), link(fa[x], rs[x]), fa[rs[x]] = fa[x];
    ls[fa[x]] = rs[x];
    fa[x] = 0; fa[root] = x; rs[x] = root;
    root = x;
}

inline void splay_max()
{
    int x = M[*--S.end()];
    if (root == x) {puts("1"); return;}
    make_root(root); access(x); splay(x);
    printf("%d\n", siz[x]);
    cut(x, fa[x]); link(x, root);
    if (ls[x]) cut(x, ls[x]), link(fa[x], ls[x]), fa[ls[x]] = fa[x];
    rs[fa[x]] = ls[x];
    fa[x] = 0; fa[root] = x; ls[x] = root;
    root = x;
}

inline void del_min()
{
    int x = M[*S.begin()];  S.erase(S.begin());
    if (root == x) {puts("1"); if (rs[x]) cut(x, rs[x]); fa[rs[x]] = 0; root = rs[x]; return;}
    make_root(root); access(x); splay(x);
    printf("%d\n", siz[x]);
    cut(x, fa[x]);
    if (rs[x]) cut(x, rs[x]), link(fa[x], rs[x]), fa[rs[x]] = fa[x];
    ls[fa[x]] = rs[x];
}

void del_max()
{
    int x = M[*--S.end()];  S.erase(--S.end());
    if (root == x) {puts("1"); if (ls[x]) cut(x, ls[x]); fa[ls[x]] = 0; root = ls[x]; return;}
    make_root(root); access(x); splay(x);
    printf("%d\n", siz[x]);
    cut(x, fa[x]);
    if (ls[x]) cut(x, ls[x]), link(fa[x], ls[x]), fa[ls[x]] = fa[x];
    rs[fa[x]] = ls[x];
}

int main()
{
    m = gi();
    while (m--) {
        int c = gi(); 
        if (c == 1) insert(gi());
        else if (c == 2) splay_min();
        else if (c == 3) splay_max();
        else if (c == 4) del_min();
        else if (c == 5) del_max();     
    }

    return 0;
}

你可能感兴趣的:(文章类型——题解,数据结构——动态树/LCT,source——各省省选)