splay 学习笔记

来源:互联网 发布:唯品会类似淘宝客 编辑:程序博客网 时间:2024/06/05 14:43

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 100100using 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 100100using 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);}
原创粉丝点击