非旋Treap的區間翻轉(文藝平衡樹)

前言

在學習這一節之前顯然要先會非旋Treap的基本操作
S p l i t M e r g e 就可以了

正題

首先,我們用Treap的中序遍曆來代表現在的數列
顯然翻轉區間相當於交換子樹
同時值得注意的是堆的性質不會影響到樹的中序遍曆(這個自己要想一想)
我們在之前強調 M e r g e ( a , b ) 的大小問題,在這裡只要按照原來樹的順序搞就行了,他已經不是搜索二叉樹了,維持形態即可
翻轉需要rev的懶惰標記
S p l i t , M e r g e 時要下推,否則之後的操作就錯了,因為作用區間錯了
沒什麼可說了直接看代碼

#include<cstdio>
#include<iostream>
using namespace std;
inline void read(int &x)
{
  int s=0,w=1;
  char c=getchar();
  while(c<'0'||c>'9')
  {
    if(c=='-')w=-1;
    c=getchar();
  }
  while(c>='0'&&c<='9')
  {
    s=(s<<3)+(s<<1)+c-'0';
    c=getchar();
  }
  x=s*w;
}
inline void write(int x)
{
  if(x<0)putchar('-'),x=-x;
  if(x>9)write(x/10);
  putchar('0'+x%10);
}
template<class a,class b>class Pair
{
public:
  a first;
  b second;
  Pair(a x,b y){first=x,second=y;}
  Pair(){}
};
int seed=2333;
inline int Random(){return seed=seed*seed+seed;}
struct node
{
  int val,key,size;
  node *son[2];
  bool rev;
  node(const int &x);
  inline void push_up(){size=son[0]->size+son[1]->size+1;}
  inline void push_down();
}*nil=new node(0),*Root;
node::node(const int &x)
{
  val=x,key=Random(),size=1,son[0]=son[1]=nil,rev=false;
}
inline void node::push_down()
{
  if(!rev)return ;
  son[0]->rev^=1,son[1]->rev^=1;
  rev=0;
  swap(son[0],son[1]);
}
Pair<node*,node*>split(node *root,int k)
{
  if(root==nil)return Pair<node*,node*>(nil,nil);
  Pair<node*,node*>p;
  if(root->rev)root->push_down();
  if(root->son[0]->size>=k)
  {
    p=split(root->son[0],k);
    root->son[0]=p.second;
    root->push_up();
    p.second=root;
    return p;
  }
  else
  {
    p=split(root->son[1],k-root->son[0]->size-1);
    root->son[1]=p.first;
    root->push_up();
    p.first=root;
    return p;
  }
}
node *merge(node *a,node *b)
{
  if(a==nil)return b;
  if(b==nil)return a;
  if(a->key<b->key)
  {
    if(a->rev)a->push_down();
    a->son[1]=merge(a->son[1],b);
    a->push_up();
    return a;
  }
  else
  {
    if(b->rev)b->push_down();
    b->son[0]=merge(a,b->son[0]);
    b->push_up();
    return b;
  }
}
void work(node *root)
{
  if(root==nil)return ;
  if(root->rev)root->push_down();
  work(root->son[0]),write(root->val),putchar(' '),work(root->son[1]);
}
int n,m,l,r;
int main()
{
  nil->size=0,Root=nil;
  read(n),read(m);
  for(int i=1;i<=n;i++)Root=merge(Root,new node(i));
  while(m--)
  {
    read(l),read(r);
    Pair<node*,node*>p=split(Root,l-1);
    Pair<node*,node*>t=split(p.second,r-l+1);
    t.first->rev^=1;
    Root=merge(p.first,merge(t.first,t.second));
  }
  work(Root);
}

偷偷說一句,我寫的Splay沒有我寫的非旋Treap跑得快
这里写图片描述这里写图片描述这里写图片描述

猜你喜欢

转载自blog.csdn.net/assass_cannotin/article/details/79311113
今日推荐