Splay

 

#include <splay.tree> #define cat Catherine

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的左儿子中了,然后有什么操作的话,我们就对区间进行标记来记录这个区间是否需要被翻转,实际上就是一直交换左右儿子,每个点维护的值最终被转到的位置就是树中序遍历之后的位置。

#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(x, y)的含义是向上翻转x直到x的father变成y

注意:以上代码中rotate函数里只update了fnow可能导致x的sub_size出错,但是不知道为什么对于这道题的答案没有影响,大部分的题解都会在后面加一个update(x),经验证加上当然还是对的。

[Splay伸展树]splay树入门级教程_SKY的C的博客-CSDN博客

#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;

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;
int n, a1, sum;
bool flag;

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 rotate(int x)
{
    int fnow = s[x].f, ffnow = s[fnow].f;
    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); update(x);
}

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;
}

void BST_insert(int dat, int x)
{
    if(dat == s[x].val)
    {
        flag = false; splay(x, 0); return;
    }
    if(dat < s[x].val)
    {
        if(s[x].son[0] == 0)
        {
            s[x].son[0] = wz; s[wz].f = x; s[wz].val = dat;
            //s[wz].son[0] = s[wz].son[1] = 0;
        }
        else BST_insert(dat, s[x].son[0]);
    }
    else
    {
        if(s[x].son[1] == 0)
        {
            s[x].son[1] = wz; s[wz].f = x; s[wz].val = dat;
        }
        else BST_insert(dat, s[x].son[1]);
    }
}

int get_pre(int x)
{
    int y = s[x].son[0]; if(y == 0) return -1;
    while(s[y].son[1] != 0) y = s[y].son[1];
    return y;
}

int get_nxt(int x)
{
    int y = s[x].son[1]; if(y == 0) return -1;
    while(s[y].son[0] != 0) y = s[y].son[0];
    return y;
}

void insert(int dat)
{
    flag = true; wz++;
    BST_insert(dat, root);
    if(flag == false) return;
    splay(wz, 0);

    int pre = get_pre(wz), nxt = get_nxt(wz);
    //printf("pre=%d nxt=%d\n", pre, nxt);
    int Min = INF;
    if(pre != -1) Min = min(Min, dat-s[pre].val);
    if(nxt != -1) Min = min(Min, s[nxt].val-dat);
    sum += Min;
    //printf("sum=%d\n", sum);
}

int main()
{
    //freopen("1.txt", "r", stdin);

    //orig[1] = -INF; orig[2] = INF;
    //root = build_tree(1, 2, 0);

    scanf("%d%d", &n, &a1);
    sum = a1; wz++;
    //s[wz].f = s[wz].son[0] = s[wz].son[1] = 0;
    s[wz].val = a1; root = wz;

    for(int i=1; i<=n-1; i++)
    {
        int dats = read();
        //printf("dats=%d\n", dats);
        insert(dats);
    }
    printf("%d", sum);

    return 0;
}
营业额统计

 

posted @ 2022-06-12 12:25  Catherine_leah  阅读(115)  评论(0编辑  收藏  举报
/* */