splay 学习笔记

1.维护BST
例:BZOJ 1588
splay 通过旋转保证时间复杂度
定义 u.lson.x < u.x < u.rson.x (BST定义)

旋转与splay(将点v旋转至根)

inline void lnk(int u,int f,int k) {T[u].fa = f;  T[f].son[k] = u;}
inline void rot(int v) {
    int u = T[v].fa, k = (T[u].son[0] == v) ? 0 : 1;
    lnk(v,T[u].fa,(T[T[u].fa].son[0] == u) ? 0 : 1);
    lnk(T[v].son[!k],u,k);  lnk(u,v,!k);
}
inline void splay(int v) {
    for (int u;u=T[v].fa;rot(v)) if (T[u].fa) rot(((T[T[v].fa].son[0] == v) ^ (T[T[u].fa].son[0] == u)) ? v : u);
}
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100100
using namespace std;

struct node {int son[2],fa,x;} T[N];

inline void lnk(int u,int f,int k) {T[u].fa = f;  T[f].son[k] = u;}
inline void rot(int v) {
    int u = T[v].fa, k = (T[u].son[0] == v) ? 0 : 1;
    lnk(v,T[u].fa,(T[T[u].fa].son[0] == u) ? 0 : 1);
    lnk(T[v].son[!k],u,k);  lnk(u,v,!k);
}

void splay(int v) {
    for (int u;u=T[v].fa;rot(v)) if (T[u].fa) rot(((T[T[v].fa].son[0] == v) ^ (T[T[u].fa].son[0] == u)) ? v : u);
}

int n,now = 1,i,x,p,q,ans,root;
inline bool set(int u,int x) {
    while (T[u].x != x && T[u].son[T[u].x < x]) u = T[u].son[T[u].x < x];
    if (T[u].x == x) {splay(root = u);  return true;}
    else {
        T[T[u].son[T[u].x < x] = ++now] = (node) {0,0,u,x};
        splay(root = now);  return false;
    }
}

int pre(int u) {if (!u) return 0xbfffffff;  while (T[u].son[1]) u = T[u].son[1];  return T[u].x;}
int suc(int u) {if (!u) return 0x3fffffff;  while (T[u].son[0]) u = T[u].son[0];  return T[u].x;}

int main() { freopen("_in.txt","r",stdin); 
    scanf("%d%d",&n,&x);  ans = T[root = now = 1].x = x;
    while (--n) {
        scanf("%d",&x);
        if (set(root,x)) continue;
        ans += min(x-pre(T[root].son[0]),suc(T[root].son[1])-x);
    } printf("%d",ans);
}

2.线段树+
例题:luogu3391
无论 splay 怎么旋转,中序遍历不变
理论上 splay 可以实现线段树的所有操作 (包括lazy_tag)
因此可用 splay 处理区间反转问题

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100100
using namespace std;

struct node {int son[2],fa,x,sum,lazy;} T[N];
int root,now,n,m,i;

inline void lnk(int u,int f,int k) {T[u].fa = f;  T[f].son[k] = u;}
inline void rot(int v) {
    int u = T[v].fa, k = T[u].son[1] == v;
    lnk(v,T[u].fa,T[T[u].fa].son[1] == u);
    lnk(T[v].son[!k],u,k);  lnk(u,v,!k);
    T[u].sum = T[T[u].son[0]].sum + T[T[u].son[1]].sum + 1;
    T[v].sum = T[T[v].son[0]].sum + T[T[v].son[1]].sum + 1;
}
inline void splay(int v,int to) {
    for (int u;(u=T[v].fa) != to && u;rot(v)) if (T[u].fa != to && u) rot(((T[T[u].fa].son[1] == u) ^ (T[T[u].fa].son[1] == u)) ? v : u);
    if (!to) root = v;
}
inline void push_down(int u) {
    if (T[u].lazy) T[T[u].son[0]].lazy ^= 1, T[T[u].son[1]].lazy ^= 1, swap(T[u].son[0],T[u].son[1]), T[u].lazy = 0;
}

int build(int l=0,int r=n+1) {
    if (l > r) return 0;
    int mid = (l+r) >> 1, ls = build(l,mid-1), u = ++now, rs = build(mid+1,r);
    T[ls].fa = T[rs].fa = u;
    T[u].sum = T[T[u].son[0] = ls].sum + T[T[u].son[1] = rs].sum + 1;  T[u].x = mid;
    return u;
}
int kth(int u,int k) {
    push_down(u);
    if (k == T[T[u].son[0]].sum + 1) return u;
    if (k <= T[T[u].son[0]].sum) return kth(T[u].son[0],k);  else return kth(T[u].son[1],k - T[T[u].son[0]].sum - 1);
}

void dfs(int u) {
    if (!u) return;  push_down(u);
    dfs(T[u].son[0]);
    if (T[u].x != 0 && T[u].x != n+1) printf("%d ",T[u].x);
    dfs(T[u].son[1]);
}


int main() {
    scanf("%d%d",&n,&m);
    root = build(0,n+1);

    for (int ql,qr;m--;) {
        scanf("%d%d",&ql,&qr);
        ql = kth(root,ql);  qr = kth(root,qr+2);
        splay(ql,0);  splay(qr,ql);

        T[T[qr].son[0]].lazy ^= 1;
    }
    dfs(root);  putchar(10);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值