洛谷 P3391【模板】文艺平衡树(Splay)

题目背景

这是一道经典的Splay模板题——文艺平衡树。

题目描述

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1

输入输出格式

输入格式:

第一行为n,m n表示初始序列有n个数,这个序列依次是 (1,2, \cdots n-1,n)(1,2,⋯n−1,n) m表示翻转操作次数

接下来m行每行两个数 [l,r][l,r] 数据保证 1 \leq l \leq r \leq n 1≤l≤r≤n

输出格式:

输出一行n个数字,表示原始序列经过m次变换后的结果

输入输出样例

输入样例#1:
5 3
1 3
1 3
1 4
输出样例#1:
4 3 2 1 5

说明

\(n, m \leq 100000\)

思路见注释。

代码:

#include<iostream>
#include<cstdio>
#define maxn 200001
using namespace std;
inline int qread() {
  char c=getchar();int num=0,f=1;
  for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  for(;isdigit(c);c=getchar()) num=num*10+c-'0';
  return num*f;
}
struct tree {
  int ch[2];
  int ff,v,size,lazy;
  void init(int x,int fa) {
    ff=ch[0]=ch[1]=0;
    size=1;
    v=x;
    ff=fa;
  }
} t[maxn];
int n,root,m,tot;
inline void pushup(int x) {
  t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
}
inline void pushdown(int x) {
  if(t[x].lazy) {
    t[t[x].ch[0]].lazy^=1;
    t[t[x].ch[1]].lazy^=1;
    t[x].lazy=0;
    swap(t[x].ch[0],t[x].ch[1]);
  }
}
void rotate(int x) {
  int y=t[x].ff;        //x的父亲 。
  int z=t[y].ff;         //x的爷爷。
  int k=t[y].ch[1]==x;         //x是y的哪一个儿子。
  t[z].ch[t[z].ch[1]==y]=x;  //z的原来的y的位置变为x。
  t[x].ff=z;                    //x的父亲变为z。
  t[y].ch[k]=t[x].ch[k^1];      //x的与x原来在y的相对的那个儿子变成y的儿子。
  t[t[x].ch[k^1]].ff=y;     //更新父节点。
  t[x].ch[k^1]=y;        //x的与x原来相对位置的儿子变成y。
  t[y].ff=x;       //更新父节点。
  pushup(y);
  pushup(x);
}
inline void splay(int x,int goal) { //将x转为goal的儿子,若x为0,则旋转为根。
  while(t[x].ff!=goal) {    //一直转到x成为goal的儿子。
    int y=t[x].ff,z=t[y].ff;     //父节点祖父节点。
    if(z!=goal)
      (t[z].ch[0]==y)^(t[y].ch[0]==x)?rotate(x):rotate(y);  //分情况。
    rotate(x);          //无论什么情况都要最后旋转x。
  }
  if(!goal)             //若goal为0,则更新x为根节点。
    root=x;
}
inline void insert(int x) {
  int u=root,ff=0;
  while(u) ff=u,u=t[u].ch[x>t[u].v];
  u=++tot;
  if(ff) t[ff].ch[x>t[ff].v]=u;
  t[u].init(x,ff);
  splay(u,0);
}
inline int kth(int k) {
  int u=root;
  while(1) {
    pushdown(u);
    if(t[t[u].ch[0]].size>=k) u=t[u].ch[0];
    else if(t[t[u].ch[0]].size+1==k) return u;
    else k-=t[t[u].ch[0]].size+1,u=t[u].ch[1];
  }
}
void write(int u) {
  pushdown(u);
  if(t[u].ch[0]) write(t[u].ch[0]);
  if(t[u].v>1&&t[u].v<n+2) printf("%d ",t[u].v-1);
  if(t[u].ch[1]) write(t[u].ch[1]);
}
inline void work(int l,int r) {
  l=kth(l);
  r=kth(r+2);
  splay(l,0);
  splay(r,l);
  t[t[t[root].ch[1]].ch[0]].lazy^=1;
}
int main() {
  n=qread(),m=qread();
  for(int i=1; i<=n+2; ++i) insert(i);
  while(m--) {
    int l=qread(),r=qread();
    work(l,r);
  }
  write(root);
  printf("\n");
  return 0;
}

转载于:https://www.cnblogs.com/grcyh/p/10569516.html

当然可以,以下是一个简单的 Splay 平衡树实现代码(C++): ```c++ #include <iostream> using namespace std; struct Node { int val; Node *left, *right, *p; Node(int v) : val(v), left(nullptr), right(nullptr), p(nullptr) {} }; class SplayTree { private: Node *root; void left_rotate(Node *x) { Node *y = x->right; x->right = y->left; if (y->left != nullptr) { y->left->p = x; } y->p = x->p; if (x->p == nullptr) { root = y; } else if (x == x->p->left) { x->p->left = y; } else { x->p->right = y; } y->left = x; x->p = y; } void right_rotate(Node *x) { Node *y = x->left; x->left = y->right; if (y->right != nullptr) { y->right->p = x; } y->p = x->p; if (x->p == nullptr) { root = y; } else if (x == x->p->left) { x->p->left = y; } else { x->p->right = y; } y->right = x; x->p = y; } void splay(Node *x) { while (x->p != nullptr) { if (x->p->p == nullptr) { if (x == x->p->left) { right_rotate(x->p); } else { left_rotate(x->p); } } else if (x == x->p->left && x->p == x->p->p->left) { right_rotate(x->p->p); right_rotate(x->p); } else if (x == x->p->right && x->p == x->p->p->right) { left_rotate(x->p->p); left_rotate(x->p); } else if (x == x->p->right && x->p == x->p->p->left) { left_rotate(x->p); right_rotate(x->p); } else { right_rotate(x->p); left_rotate(x->p); } } } public: SplayTree() : root(nullptr) {} Node* search(int v) { Node *x = root; while (x != nullptr && x->val != v) { if (v < x->val) { x = x->left; } else { x = x->right; } } if (x != nullptr) { splay(x); } return x; } void insert(int v) { Node *z = new Node(v); Node *y = nullptr; Node *x = root; while (x != nullptr) { y = x; if (z->val < x->val) { x = x->left; } else { x = x->right; } } z->p = y; if (y == nullptr) { root = z; } else if (z->val < y->val) { y->left = z; } else { y->right = z; } splay(z); } void remove(int v) { Node *z = search(v); if (z == nullptr) { return; } if (z->left == nullptr) { transplant(z, z->right); } else if (z->right == nullptr) { transplant(z, z->left); } else { Node *y = minimum(z->right); if (y->p != z) { transplant(y, y->right); y->right = z->right; y->right->p = y; } transplant(z, y); y->left = z->left; y->left->p = y; } delete z; } Node* minimum(Node *x) { while (x->left != nullptr) { x = x->left; } return x; } Node* maximum(Node *x) { while (x->right != nullptr) { x = x->right; } return x; } void inorder_walk() { inorder_walk(root); cout << endl; } private: void transplant(Node *u, Node *v) { if (u->p == nullptr) { root = v; } else if (u == u->p->left) { u->p->left = v; } else { u->p->right = v; } if (v != nullptr) { v->p = u->p; } } void inorder_walk(Node *x) { if (x != nullptr) { inorder_walk(x->left); cout << x->val << ' '; inorder_walk(x->right); } } }; int main() { SplayTree tree; tree.insert(5); tree.insert(2); tree.insert(8); tree.insert(1); tree.insert(3); tree.insert(7); tree.insert(9); tree.inorder_walk(); // output: 1 2 3 5 7 8 9 tree.remove(5); tree.inorder_walk(); // output: 1 2 3 7 8 9 tree.search(7); tree.inorder_walk(); // output: 1 2 3 7 8 9 return 0; } ``` 以上代码实现了 Splay 平衡树的基本操作,包括插入、删除、查找、中序遍历等。如果你需要进一步了解 Splay 平衡树,可以参考相关资料。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值