其他分享
首页 > 其他分享> > Splay

Splay

作者:互联网

 

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1e6 + 5;
const int mod = 1e9 + 7;
const int INF = 2147483647;

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct Splay_tree
{
    int f, sub_size, cnt, val, tag;
    int son[2];
}s[maxn];
int orig[maxn], root, wz;

inline bool which(int x)
{
    return x == s[s[x].f].son[1];
}

inline void update(int x)
{
    if(x)
    {
        s[x].sub_size = s[x].cnt;
        if(s[x].son[0]) s[x].sub_size += s[s[x].son[0]].sub_size;
        if(s[x].son[1]) s[x].sub_size += s[s[x].son[1]].sub_size;
    }
}

inline void pushdown(int x)
{
    if(x && s[x].tag)
    {
        s[s[x].son[1]].tag ^= 1;
        s[s[x].son[0]].tag ^= 1;
        swap(s[x].son[1], s[x].son[0]);
        s[x].tag = 0;
    }
}

inline void rotate(int x)
{
    int fnow = s[x].f, ffnow = s[fnow].f;
    pushdown(x), pushdown(fnow);
    bool w = which(x);
    s[fnow].son[w] = s[x].son[w^1];
    s[s[fnow].son[w]].f = fnow;
    s[fnow].f = x;
    s[x].f = ffnow;
    s[x].son[w^1] = fnow;
    if(ffnow)
    {
        s[ffnow].son[s[ffnow].son[1]==fnow] = x;
    }
    update(fnow);
}

inline void splay(int x, int goal)
{
    for(int qwq; (qwq=s[x].f)!=goal; rotate(x))
    {
        if(s[qwq].f != goal)
        {
            rotate(which(x) == which(qwq) ? qwq : x);
        }
    }
    if(goal == 0)
    {
        root = x;
    }
}

int build_tree(int l, int r, int fa)
{
    if(l > r) return 0;
    int mid = (l + r) >> 1;
    int now = ++wz;
    s[now].f = fa;
    s[now].son[0] = s[now].son[1] = 0;
    s[now].cnt++;
    s[now].val = orig[mid];
    s[now].sub_size++;
    s[now].son[0] = build_tree(l, mid-1, now);
    s[now].son[1] = build_tree(mid+1, r, now);
    update(now);
    return now;
}

inline int find(int x)//GetvalByRank
{
    int now = root;
    while(1)
    {
        pushdown(now);
        if(x <= s[s[now].son[0]].sub_size)
        {
            now = s[now].son[0];
        }
        else
        {
            x -= s[s[now].son[0]].sub_size + 1;
            if(!x) return now;
            now = s[now].son[1];
        }
    }
}

inline void reverse(int x, int y)
{
    int l = x - 1, r = y + 1;
    l = find(l), r = find(r);
    splay(l, 0);
    splay(r, l);
    int pos = s[root].son[1];
    pos = s[pos].son[0];
    s[pos].tag ^= 1;
}

inline void dfs(int now)
{
    pushdown(now);
    if(s[now].son[0]) dfs(s[now].son[0]);
    if(s[now].val != -INF && s[now].val != INF)
    {
        printf("%d ", s[now].val);
    }
    if(s[now].son[1]) dfs(s[now].son[1]);
}

int main()
{
    int n, m, x, y;
    scanf("%d%d", &n, &m);
    orig[1] = -INF; orig[n+2] = INF;
    for(int i=1; i<=n; i++)
    {
        orig[i+1] = i;
    }
    root = build_tree(1, n+2, 0);
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d", &x, &y);
        reverse(x+1, y+1);
    }
    dfs(root);

    return 0;
}

 

 

Splay依靠的并不是完全的平衡,根据90-10法则,90%的询问都发生在10%的数据上。

Splay的原理就是:找到询问频率最高的点,把它旋转到根节点,以此在下面的询问中提高效率。

我们认为,我正在访问的点就是询问频率最高的点。

让x成为树根(y):

1.如果y是x的父亲,向上旋x

2.如果x和x的父亲在树上偏的方向相同(左or右孩子),先让x的父亲向上旋,再旋x

3.else让x连续旋两次

//为什么分情况?可以自行画图看一看

//发现按照上述旋转,每次splay以后,整棵树十分的平衡!(接近于完全二叉树)

//如果不分情况,直接无脑上旋,则会结构变得比较乱

前驱、后继

首先,插入目标新节点,使该节点在根上
那么它的前驱为左子树中最大的那个
后继为右子树中最小的那个
最后,当然要删掉刚才插入的节点

文艺平衡树

建树:
就像给线段树建树一样,但是在原数组的基础上加一个-INF,+INF。(比如原序列是1,2,3,4。你建树的时候要给-INF,1,2,3,4,+INF建树)
至于为什么这样做,就是为了可以给区间[ 1,n ]倒置,还可以防止pre和nxt找不到

and then:

当操作到区间【l,r】的时候我们就把 l-1 旋到根的位置上去,再把 r + 1旋到根的右儿子位置处,如此,我们需要的区间【l,r】便都处在r+1的左儿子中了,然后有什么操作的话,我们就对区间进行标记来记录这个区间是否需要被翻转,实际上就是一直交换左右儿子,每个点维护的值最终被转到的位置就是树中序遍历之后的位置。

 

标签:ch,int,mid,son,Splay,INF,now
来源: https://www.cnblogs.com/Catherine2006/p/16367761.html