2013-team4/code/splay
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
const int INF = 2147480000, N = 200100;
struct Node{
int size;
Node *f, *ch[2];
int v, rev, add, mx; // 根据题意具体修改
int lr(); // 返回自己是左(0) / 右(1)儿子
void rotate(); // 向上旋转
Node* splay(Node *goal); // splay 到某结点下, 不传参数则到根
Node* set(int d, Node *c); // 设置左(0) / 右(1)儿子
Node* pushDown(); // 标记下传
Node* update(); // 用儿子的信息更新自己
void exeAdd(int a){
add += a;
v += a;
mx += a;
}
}pool[N], *null; // 内存池, null 替代 NULL
int Node::lr(){
return int(f->ch[1] == this);
}
Node* Node::set(int d, Node *c){
ch[d] = c;
return c->f = this;
}
void Node::rotate(){
Node *x = f;
int d = lr() ^ 1;
x->set(d ^ 1, ch[d]);
x->f->set(x->lr(), this);
set(d, x);
x->update();
update();
}
Node* Node::splay(Node *goal = null){
for(pushDown(); f != goal; rotate()){
f->f->pushDown();
f->pushDown();
pushDown();
if(f->f != goal){
if(f->lr() == lr()) f->rotate();
else rotate();
}
}
return this;
}
// 根据题意具体修改
Node* Node::update(){
if(this != null){
size = ch[0]->size + ch[1]->size + 1;
mx = max(v, max(ch[0]->mx, ch[1]->mx));
}
return this;
}
// 根据题意具体修改
Node* Node::pushDown(){
if(this != null){
if(rev){
swap(ch[0], ch[1]);
for(int i = 0; i < 2; i++) if(ch[i] != null)
ch[i]->rev ^= 1;
rev = 0;
}
if(add != 0){
for(int i = 0; i < 2; i++) if(ch[i] != null)
ch[i]->exeAdd(add);
add = 0;
}
}
return this;
}
int Cnt;
// 根据题意具体修改
Node* newNode(int val){
Node *p = &pool[Cnt++];
p->f = p->ch[0] = p->ch[1] = null;
p->size = 1;
p->rev = 0;
p->v = val;
p->mx = val;
p->add = 0;
return p;
}
// !!! 必须先调用 init
void init(){
Cnt = 0;
null = newNode(-INF);
null->size = 0;
}
// 用 a[l, r] 建立平衡的树, 返回树根
Node* build(int l, int r, int a[]){
if(l > r) return null;
int mid = (l + r) / 2;
Node *p = newNode(a[mid]);
if(l < r){
p->set(0, build(l, mid - 1, a));
p->set(1, build(mid + 1, r, a));
p->update();
}
return p;
}
// 返回树中第 k 个结点, 下标从 1 开始
Node* select(Node *root, int k){
for(Node *p = root; true; ){
p->pushDown();
int lsize = p->ch[0]->size;
if(k <= lsize) p = p->ch[0];
else{
k -= lsize + 1;
if(k == 0) return p;
p = p->ch[1];
}
}
}
// 返回 [l, r] 的子树, 会修改根
Node* range(Node *&root, int l, int r){
if(l == 1 && r == root->size) return root;
if(l == 1){
root = select(root, r + 1)->splay();
return root->ch[0];
}
root = select(root, l - 1)->splay();
if(r == root->size) return root->ch[1];
return select(root, r + 1)->splay(root)->ch[0];
}
// 翻转 [l, r] 区间, 返回树根
Node* reverse(Node *root, int l, int r){
range(root, l, r)->rev ^= 1;
return root;
}
// 合并两棵树, 返回树根
Node* merge(Node *p, Node *q){
p->f = q->f = null;
if(p == null) return q;
if(q == null) return p;
q = select(q, 1);
return q->splay()->set(0, p)->update();
}
// 删除以 p 为根的子树, 返回树根
Node* erase(Node *p){
if(p->f == null) return null;
Node *q = p->f->pushDown();
return q->set(p->lr(), null)->update()->splay();
}
// 删除第 k 个元素, 返回树根
Node* erase(Node *root, int k){
Node *p = select(root, k)->splay();
return merge(p->ch[0], p->ch[1]);
}
// 在 p 之前插入 q, 返回树根
Node* insert(Node *p, Node *q){
p->splay();
if(p->ch[0] == null){
p->set(0, q);
}
else{
select(p, p->ch[0]->size)->splay(p)->set(1, q)->update();
}
p->update();
return p;
}
// 在第 k 个元素前插入 p, 返回树根
Node* insert(Node *root, int k, Node *p){
if(root == null) return p;
if(k > root->size){
return select(root, root->size)->splay()->set(1, p)->update();
}
else{
return insert(select(root, k), p);
}
}
// 给 [l, r] 区间加上一个数, 返回树根
Node* addVal(Node *root, int l, int r, int val){
Node *p = range(root, l, r);
p->exeAdd(val);
return p->splay();
}
// 将 [l, r] 区间循环右移 t 位
Node* revolve(Node *root, int l, int r, int t){
if(t == 0) return root;
Node *p = range(root, r - t + 1, r);
root = erase(p); p->f = null;
return insert(root, l, p);
}
// 区间查询最大值
Node* queryMax(Node *root, int l, int r){
Node *p = range(root, l, r);
cout << p->mx << endl;
return root;
}
}}}
{{{
/*
Splay模板 by zimpha
这道题目是POJ 3580 SuperMemo
实现了rot, splay, select, get_seq等基本功能
实现了区间反转,整段区间操作(+,覆盖之类的),插入一个数,删除一个数
要获取区间[l, r]直接调用get_seq(l-1, r+1)即可。
每次使用前必须先调用init()函数
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int MAXN=100000+10;
const int inf=~0U>>2;
struct node {
node *ch[2], *p;
int size, add, val, Min, rev;
node () {size=0; val=inf;}
bool d() {return this==p->ch[1];}
void setc(node *c, int d) {ch[d]=c; c->p=this;}
void markAdd(int _add) {
add+=_add, val+=_add, Min+=_add;
}
void markRev() {
rev^=1; swap(ch[0], ch[1]);
}
void update() {
size=ch[0]->size+ch[1]->size+1;
Min=min(val, min(ch[0]->Min, ch[1]->Min));
}
}*null, *root;
node mem[MAXN*2], *stk[MAXN*2];
int A[MAXN], N, M, top;
inline void pushdown(node *t) {
if (t==null) return;
if (t->add) {
if (t->ch[0]!=null) t->ch[0]->markAdd(t->add);
if (t->ch[1]!=null) t->ch[1]->markAdd(t->add);
}
if (t->rev) {
if (t->ch[0]!=null) t->ch[0]->markRev();
if (t->ch[1]!=null) t->ch[1]->markRev();
}
t->add=t->rev=0;
}
inline node *new_node(int v) {
node *ret=stk[--top];
ret->val=v; ret->size=1; ret->Min=v; ret->add=0;
ret->ch[0]=ret->ch[1]=ret->p=null;
return ret;
}
inline void recycle(node *x) {
stk[top++]=x;
}
inline node* rot(node *t) {
node *p=t->p;
pushdown(p); pushdown(t);
int d=t->d();
p->p->setc(t, p->d());
p->setc(t->ch[!d], d);
t->setc(p, !d);
p->update();
if (p==root) root=t;
return t;
}
inline void splay(node *t, node *f) {
for (pushdown(t); t->p!=f;) {
if (t->p->p==f) rot(t);
else t->d()==t->p->d() ? (rot(t->p), rot(t)) : (rot(t), rot(t));
}
t->update();
}
inline node *select(int k) {
for (node *t=root;;) {
pushdown(t);
int c=t->ch[0]->size;
if (k==c) return t;
if (k>c) k-=c+1, t=t->ch[1];
else t=t->ch[0];
}
return null;
}
inline node *get_seq(int l, int r) {
node *L=select(l); splay(L, null);
node *R=select(r); splay(R, root);
return root->ch[1]->ch[0];
}
node *build_tree(int *l, int *r) {
if (l>=r) return null;
if (l+1==r) return new_node(*l);
int *m=l+(r-l)/2;
node *t=new_node(*m);
t->setc(build_tree(l, m), 0);
t->setc(build_tree(m+1, r), 1);
t->update(); return t;
}
void init() {
for (int i=0; i<2*MAXN; i++) stk[i]=mem+i; top=MAXN*2;
null=new_node(inf); null->size=0; null->Min=inf;
null->ch[0]=null->ch[1]=null->p=null;
A[0]=A[N+1]=inf;
root=build_tree(A, A+N+2);
}
void ADD() {
int x, y, D; scanf("%d%d%d", &x, &y, &D);
node *t=get_seq(x-1, y+1);
t->markAdd(D); splay(t, null);
}
void REVERSE() {
int x, y; scanf("%d%d", &x, &y);
node *t=get_seq(x-1, y+1);
t->markRev(); splay(t, null);
}
void REVOLVE() {
int x, y, T; scanf("%d%d%d", &x, &y, &T);
int n=y-x+1; T%=n; if (T==0) return;
node *t=get_seq(x-1, x+n-T);
t->p->setc(null, 0); splay(root->ch[1], null);
get_seq(x+T-1, x+T);
root->ch[1]->setc(t, 0); splay(t, null);
}
void INSERT() {
int x, P; scanf("%d%d", &x, &P); A[0]=P;
node *t=build_tree(A, A+1);
get_seq(x, x+1);
root->ch[1]->setc(t, 0);
splay(t, null);
}
void DELETE() {
int x; scanf("%d", &x);
node *t=get_seq(x-1, x+1);
t->p->setc(null, 0); splay(root->ch[1], null);
recycle(t);
}
void MIN() {
int x, y; scanf("%d%d", &x, &y);
node *t=get_seq(x-1, y+1);
printf("%d\n", t->Min);
}
int main() {
scanf("%d", &N);
for (int i=1; i<=N; i++) scanf("%d", A+i);
init();
scanf("%d", &M);
while (M--) {
char CMD[20];
scanf("%s", CMD);
if (CMD[0]=='A') ADD();
else if (CMD[0]=='I') INSERT();
else if (CMD[0]=='D') DELETE();
else if (CMD[0]=='M') MIN();
else if (CMD[3]=='E') REVERSE();
else if (CMD[3]=='O') REVOLVE();
}
return 0;
}
}}}
const int INF = 2147480000, N = 200100;
struct Node{
int size;
Node *f, *ch[2];
int v, rev, add, mx; // 根据题意具体修改
int lr(); // 返回自己是左(0) / 右(1)儿子
void rotate(); // 向上旋转
Node* splay(Node *goal); // splay 到某结点下, 不传参数则到根
Node* set(int d, Node *c); // 设置左(0) / 右(1)儿子
Node* pushDown(); // 标记下传
Node* update(); // 用儿子的信息更新自己
void exeAdd(int a){
add += a;
v += a;
mx += a;
}
}pool[N], *null; // 内存池, null 替代 NULL
int Node::lr(){
return int(f->ch[1] == this);
}
Node* Node::set(int d, Node *c){
ch[d] = c;
return c->f = this;
}
void Node::rotate(){
Node *x = f;
int d = lr() ^ 1;
x->set(d ^ 1, ch[d]);
x->f->set(x->lr(), this);
set(d, x);
x->update();
update();
}
Node* Node::splay(Node *goal = null){
for(pushDown(); f != goal; rotate()){
f->f->pushDown();
f->pushDown();
pushDown();
if(f->f != goal){
if(f->lr() == lr()) f->rotate();
else rotate();
}
}
return this;
}
// 根据题意具体修改
Node* Node::update(){
if(this != null){
size = ch[0]->size + ch[1]->size + 1;
mx = max(v, max(ch[0]->mx, ch[1]->mx));
}
return this;
}
// 根据题意具体修改
Node* Node::pushDown(){
if(this != null){
if(rev){
swap(ch[0], ch[1]);
for(int i = 0; i < 2; i++) if(ch[i] != null)
ch[i]->rev ^= 1;
rev = 0;
}
if(add != 0){
for(int i = 0; i < 2; i++) if(ch[i] != null)
ch[i]->exeAdd(add);
add = 0;
}
}
return this;
}
int Cnt;
// 根据题意具体修改
Node* newNode(int val){
Node *p = &pool[Cnt++];
p->f = p->ch[0] = p->ch[1] = null;
p->size = 1;
p->rev = 0;
p->v = val;
p->mx = val;
p->add = 0;
return p;
}
// !!! 必须先调用 init
void init(){
Cnt = 0;
null = newNode(-INF);
null->size = 0;
}
// 用 a[l, r] 建立平衡的树, 返回树根
Node* build(int l, int r, int a[]){
if(l > r) return null;
int mid = (l + r) / 2;
Node *p = newNode(a[mid]);
if(l < r){
p->set(0, build(l, mid - 1, a));
p->set(1, build(mid + 1, r, a));
p->update();
}
return p;
}
// 返回树中第 k 个结点, 下标从 1 开始
Node* select(Node *root, int k){
for(Node *p = root; true; ){
p->pushDown();
int lsize = p->ch[0]->size;
if(k <= lsize) p = p->ch[0];
else{
k -= lsize + 1;
if(k == 0) return p;
p = p->ch[1];
}
}
}
// 返回 [l, r] 的子树, 会修改根
Node* range(Node *&root, int l, int r){
if(l == 1 && r == root->size) return root;
if(l == 1){
root = select(root, r + 1)->splay();
return root->ch[0];
}
root = select(root, l - 1)->splay();
if(r == root->size) return root->ch[1];
return select(root, r + 1)->splay(root)->ch[0];
}
// 翻转 [l, r] 区间, 返回树根
Node* reverse(Node *root, int l, int r){
range(root, l, r)->rev ^= 1;
return root;
}
// 合并两棵树, 返回树根
Node* merge(Node *p, Node *q){
p->f = q->f = null;
if(p == null) return q;
if(q == null) return p;
q = select(q, 1);
return q->splay()->set(0, p)->update();
}
// 删除以 p 为根的子树, 返回树根
Node* erase(Node *p){
if(p->f == null) return null;
Node *q = p->f->pushDown();
return q->set(p->lr(), null)->update()->splay();
}
// 删除第 k 个元素, 返回树根
Node* erase(Node *root, int k){
Node *p = select(root, k)->splay();
return merge(p->ch[0], p->ch[1]);
}
// 在 p 之前插入 q, 返回树根
Node* insert(Node *p, Node *q){
p->splay();
if(p->ch[0] == null){
p->set(0, q);
}
else{
select(p, p->ch[0]->size)->splay(p)->set(1, q)->update();
}
p->update();
return p;
}
// 在第 k 个元素前插入 p, 返回树根
Node* insert(Node *root, int k, Node *p){
if(root == null) return p;
if(k > root->size){
return select(root, root->size)->splay()->set(1, p)->update();
}
else{
return insert(select(root, k), p);
}
}
// 给 [l, r] 区间加上一个数, 返回树根
Node* addVal(Node *root, int l, int r, int val){
Node *p = range(root, l, r);
p->exeAdd(val);
return p->splay();
}
// 将 [l, r] 区间循环右移 t 位
Node* revolve(Node *root, int l, int r, int t){
if(t == 0) return root;
Node *p = range(root, r - t + 1, r);
root = erase(p); p->f = null;
return insert(root, l, p);
}
// 区间查询最大值
Node* queryMax(Node *root, int l, int r){
Node *p = range(root, l, r);
cout << p->mx << endl;
return root;
}
/*
Splay模板 by zimpha
这道题目是POJ 3580 SuperMemo
实现了rot, splay, select, get_seq等基本功能
实现了区间反转,整段区间操作(+,覆盖之类的),插入一个数,删除一个数
要获取区间[l, r]直接调用get_seq(l-1, r+1)即可。
每次使用前必须先调用init()函数
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int MAXN=100000+10;
const int inf=~0U>>2;
struct node {
node *ch[2], *p;
int size, add, val, Min, rev;
node () {size=0; val=inf;}
bool d() {return this==p->ch[1];}
void setc(node *c, int d) {ch[d]=c; c->p=this;}
void markAdd(int _add) {
add+=_add, val+=_add, Min+=_add;
}
void markRev() {
rev^=1; swap(ch[0], ch[1]);
}
void update() {
size=ch[0]->size+ch[1]->size+1;
Min=min(val, min(ch[0]->Min, ch[1]->Min));
}
}*null, *root;
node mem[MAXN*2], *stk[MAXN*2];
int A[MAXN], N, M, top;
inline void pushdown(node *t) {
if (t==null) return;
if (t->add) {
if (t->ch[0]!=null) t->ch[0]->markAdd(t->add);
if (t->ch[1]!=null) t->ch[1]->markAdd(t->add);
}
if (t->rev) {
if (t->ch[0]!=null) t->ch[0]->markRev();
if (t->ch[1]!=null) t->ch[1]->markRev();
}
t->add=t->rev=0;
}
inline node *new_node(int v) {
node *ret=stk[--top];
ret->val=v; ret->size=1; ret->Min=v; ret->add=0;
ret->ch[0]=ret->ch[1]=ret->p=null;
return ret;
}
inline void recycle(node *x) {
stk[top++]=x;
}
inline node* rot(node *t) {
node *p=t->p;
pushdown(p); pushdown(t);
int d=t->d();
p->p->setc(t, p->d());
p->setc(t->ch[!d], d);
t->setc(p, !d);
p->update();
if (p==root) root=t;
return t;
}
inline void splay(node *t, node *f) {
for (pushdown(t); t->p!=f;) {
if (t->p->p==f) rot(t);
else t->d()==t->p->d() ? (rot(t->p), rot(t)) : (rot(t), rot(t));
}
t->update();
}
inline node *select(int k) {
for (node *t=root;;) {
pushdown(t);
int c=t->ch[0]->size;
if (k==c) return t;
if (k>c) k-=c+1, t=t->ch[1];
else t=t->ch[0];
}
return null;
}
inline node *get_seq(int l, int r) {
node *L=select(l); splay(L, null);
node *R=select(r); splay(R, root);
return root->ch[1]->ch[0];
}
node *build_tree(int *l, int *r) {
if (l>=r) return null;
if (l+1==r) return new_node(*l);
int *m=l+(r-l)/2;
node *t=new_node(*m);
t->setc(build_tree(l, m), 0);
t->setc(build_tree(m+1, r), 1);
t->update(); return t;
}
void init() {
for (int i=0; i<2*MAXN; i++) stk[i]=mem+i; top=MAXN*2;
null=new_node(inf); null->size=0; null->Min=inf;
null->ch[0]=null->ch[1]=null->p=null;
A[0]=A[N+1]=inf;
root=build_tree(A, A+N+2);
}
void ADD() {
int x, y, D; scanf("%d%d%d", &x, &y, &D);
node *t=get_seq(x-1, y+1);
t->markAdd(D); splay(t, null);
}
void REVERSE() {
int x, y; scanf("%d%d", &x, &y);
node *t=get_seq(x-1, y+1);
t->markRev(); splay(t, null);
}
void REVOLVE() {
int x, y, T; scanf("%d%d%d", &x, &y, &T);
int n=y-x+1; T%=n; if (T==0) return;
node *t=get_seq(x-1, x+n-T);
t->p->setc(null, 0); splay(root->ch[1], null);
get_seq(x+T-1, x+T);
root->ch[1]->setc(t, 0); splay(t, null);
}
void INSERT() {
int x, P; scanf("%d%d", &x, &P); A[0]=P;
node *t=build_tree(A, A+1);
get_seq(x, x+1);
root->ch[1]->setc(t, 0);
splay(t, null);
}
void DELETE() {
int x; scanf("%d", &x);
node *t=get_seq(x-1, x+1);
t->p->setc(null, 0); splay(root->ch[1], null);
recycle(t);
}
void MIN() {
int x, y; scanf("%d%d", &x, &y);
node *t=get_seq(x-1, y+1);
printf("%d\n", t->Min);
}
int main() {
scanf("%d", &N);
for (int i=1; i<=N; i++) scanf("%d", A+i);
init();
scanf("%d", &M);
while (M--) {
char CMD[20];
scanf("%s", CMD);
if (CMD[0]=='A') ADD();
else if (CMD[0]=='I') INSERT();
else if (CMD[0]=='D') DELETE();
else if (CMD[0]=='M') MIN();
else if (CMD[3]=='E') REVERSE();
else if (CMD[3]=='O') REVOLVE();
}
return 0;
}