ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Splay

2022-06-12 12:31:07  阅读:159  来源: 互联网

标签:ch int mid son Splay INF now


 

#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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有