Treap永不旋轉!!![維修數列]

前言

Splay是會轉的的好,Treap是不會轉的妙,我們不用轉也能實現神奇的操作
在這裡比較複雜的是插入區間的操作,這是Treap沒有嘗試過的

如何 O ( n ) 構造Treap?

Splay可以遞歸構造,但是Treap有key的問題,顯然不能那樣構造
那怎麼構造呢?
我們利用棧來解決這個問題
我們將每次構造出來的節點放到棧裏,當我們再次要構造一個新節點時,我們和棧頂節點比較,有兩種情況停止比較

  1. 棧頂元素key值的優先度高於新節點
  2. 棧空了

我們將最後一個彈出的節點接在新節點的左兒子上
如果棧未空,我們就將新節點接在棧頂的右兒子上
最後將新節點壓入棧
不要忘了將每個節點都Pushup一下
這個操作玄學滿足中序遍曆為原序列,而且造出了一個平衡的Treap
不知道是誰想出的神奇操作

inline node *build(int k)
{
  int top=0,a;
  for(int i=1;i<=k;i++)
  {
    read(a);
    node *temp=new node(a),*last=nil;
    while(top&&stack[top]->key>temp->key)
    stack[top]->push_up(),last=stack[top],stack[top--]=nil;
    if(top)stack[top]->son[1]=temp;
    temp->son[0]=last,stack[++top]=temp;
  }
  while(top)
  stack[top--]->push_up();
  return stack[1];
}

只有這裡最難
下面我把每個函數分開發上來

節點定義

struct node
{
  int val,key,size,sum,maxsum,lmax,rmax;
  bool rev,same;
  node *son[2];
  node(int x);
  node(){}
  ~node();
  inline void push_up();
  inline void push_down();
  inline void push_rev();
  inline void push_same(int x);
}*nil=new node(0),*Root,*stack[MAXN];

pair模板

template<class a,class b>class Pair
{
public:
  a first;
  b second;
  Pair(){}
  Pair(a x,b y){first=x,second=y;}
};

讀入輸出優化

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<='9'&&c>='0'){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(x%10+'0');
}

隨機數生成器優化

int seed=2333;
inline int Random(){return seed=seed*seed+seed+1;}

構造函數

node::node(int x)
{
  val=x,key=Random(),size=1,son[0]=son[1]=nil,lmax=rmax=maxsum=sum=val;
  rev=same=false;
}

構析函數

node::~node()
{
  if(son[0]!=nil)delete son[0];
  if(son[1]!=nil)delete son[1];
}

節點翻轉

inline void node::push_rev()
{
  if(this==nil)return ;
  rev^=1;
  swap(lmax,rmax);
}

節點賦值

inline void node::push_same(int x)
{
  if(this==nil)return ;
  same=1;
  val=x,sum=size*x;
  lmax=rmax=maxsum=max(x,x*size);
}

上傳函數

inline void node::push_up()
{
  size=son[0]->size+son[1]->size+1;
  sum=son[0]->sum+son[1]->sum+val;
  lmax=max(son[0]->lmax,max(son[0]->sum+val,son[0]->sum+val+son[1]->lmax));
  rmax=max(son[1]->rmax,max(son[1]->sum+val,son[1]->sum+val+son[0]->rmax));
  maxsum=max(max(son[0]->maxsum,son[1]->maxsum),max(0,son[0]->rmax)+max(0,son[1]->lmax)+val);
}

下傳函數

inline void node::push_down()
{
  if(this==nil)return ;
  if(rev)
  {
    rev^=1;
    son[0]->push_rev(),son[1]->push_rev();
    swap(son[0],son[1]);
  }
  if(same)
  {
    same=0;
    son[0]->push_same(val),son[1]->push_same(val);
  }
}

分裂!

Pair<node*,node*>split(node *root,int k)
{
  if(root==nil)return Pair<node*,node*>(nil,nil);
  root->push_down();
  Pair<node*,node*>p;
  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;
  a->push_down(),b->push_down();
  if(a->key<b->key)
  {
    a->son[1]=merge(a->son[1],b);
    a->push_up();
    return a;
  }
  else
  {
    b->son[0]=merge(a,b->son[0]);
    b->push_up();
    return b;
  }
}

插入區間

inline void insert(int pos,int len)
{
  node *treap=build(len);
  Pair<node*,node*>p=split(Root,pos);
  Root=merge(merge(p.first,treap),p.second);
}

刪除區間

inline void del(int pos,int len)
{
  Pair<node*,node*>a=split(Root,pos-1),b=split(a.second,len);
  Root=merge(a.first,b.second);
  delete b.first;
}

反轉區間

inline void reverse(int pos,int len)
{
  Pair<node*,node*>a=split(Root,pos-1),b=split(a.second,len);
  b.first->push_rev();
  Root=merge(a.first,merge(b.first,b.second));
}

區間賦值

inline void make_same(int pos,int len,int c)
{
  Pair<node*,node*>a=split(Root,pos-1),b=split(a.second,len);
  b.first->push_same(c);
  Root=merge(a.first,merge(b.first,b.second));
}

區間求和

inline int get_sum(int pos,int len)
{
  Pair<node*,node*>a=split(Root,pos-1),b=split(a.second,len);
  int ans=b.first->sum;
  Root=merge(a.first,merge(b.first,b.second));
  return ans;
}

最大連續子段和

這個直接查就好了吧

write(Root->maxsum),putchar(10);

这里写图片描述
附全篇AC代碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 500010
#define inf (1<<29)
using namespace std;
template<class a,class b>class Pair
{
public:
  a first;
  b second;
  Pair(){}
  Pair(a x,b y){first=x,second=y;}
};
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<='9'&&c>='0'){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(x%10+'0');
}
int seed=2333;
inline int Random(){return seed=seed*seed+seed+1;}
struct node
{
  int val,key,size,sum,maxsum,lmax,rmax;
  bool rev,same;
  node *son[2];
  node(int x);
  node(){}
  ~node();
  inline void push_up();
  inline void push_down();
  inline void push_rev();
  inline void push_same(int x);
}*nil=new node(0),*Root,*stack[MAXN];
node::node(int x)
{
  val=x,key=Random(),size=1,son[0]=son[1]=nil,lmax=rmax=maxsum=sum=val;
  rev=same=false;
}
node::~node()
{
  if(son[0]!=nil)delete son[0];
  if(son[1]!=nil)delete son[1];
}
inline void node::push_rev()
{
  if(this==nil)return ;
  rev^=1;
  swap(lmax,rmax);
}
inline void node::push_same(int x)
{
  if(this==nil)return ;
  same=1;
  val=x,sum=size*x;
  lmax=rmax=maxsum=max(x,x*size);
}
inline void node::push_up()
{
  size=son[0]->size+son[1]->size+1;
  sum=son[0]->sum+son[1]->sum+val;
  lmax=max(son[0]->lmax,max(son[0]->sum+val,son[0]->sum+val+son[1]->lmax));
  rmax=max(son[1]->rmax,max(son[1]->sum+val,son[1]->sum+val+son[0]->rmax));
  maxsum=max(max(son[0]->maxsum,son[1]->maxsum),max(0,son[0]->rmax)+max(0,son[1]->lmax)+val);
}
inline void node::push_down()
{
  if(this==nil)return ;
  if(rev)
  {
    rev^=1;
    son[0]->push_rev(),son[1]->push_rev();
    swap(son[0],son[1]);
  }
  if(same)
  {
    same=0;
    son[0]->push_same(val),son[1]->push_same(val);
  }
}
node *merge(node *a,node *b)
{
  if(a==nil)return b;
  if(b==nil)return a;
  a->push_down(),b->push_down();
  if(a->key<b->key)
  {
    a->son[1]=merge(a->son[1],b);
    a->push_up();
    return a;
  }
  else
  {
    b->son[0]=merge(a,b->son[0]);
    b->push_up();
    return b;
  }
}
Pair<node*,node*>split(node *root,int k)
{
  if(root==nil)return Pair<node*,node*>(nil,nil);
  root->push_down();
  Pair<node*,node*>p;
  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;
  }
}
inline node *build(int k)
{
  int top=0,a;
  for(int i=1;i<=k;i++)
  {
    read(a);
    node *temp=new node(a),*last=nil;
    while(top&&stack[top]->key>temp->key)
    stack[top]->push_up(),last=stack[top],stack[top--]=nil;
    if(top)stack[top]->son[1]=temp;
    temp->son[0]=last,stack[++top]=temp;
  }
  while(top)
  stack[top--]->push_up();
  return stack[1];
}
inline void insert(int pos,int len)
{
  node *treap=build(len);
  Pair<node*,node*>p=split(Root,pos);
  Root=merge(merge(p.first,treap),p.second);
}
inline void del(int pos,int len)
{
  Pair<node*,node*>a=split(Root,pos-1),b=split(a.second,len);
  Root=merge(a.first,b.second);
  delete b.first;
}
inline void reverse(int pos,int len)
{
  Pair<node*,node*>a=split(Root,pos-1),b=split(a.second,len);
  b.first->push_rev();
  Root=merge(a.first,merge(b.first,b.second));
}
inline void make_same(int pos,int len,int c)
{
  Pair<node*,node*>a=split(Root,pos-1),b=split(a.second,len);
  b.first->push_same(c);
  Root=merge(a.first,merge(b.first,b.second));
}
inline int get_sum(int pos,int len)
{
  Pair<node*,node*>a=split(Root,pos-1),b=split(a.second,len);
  int ans=b.first->sum;
  Root=merge(a.first,merge(b.first,b.second));
  return ans;
}
char opt[10];
int n,m,a,b,c;
int main()
{
  nil->size=0;
  nil->lmax=nil->rmax=nil->maxsum=-inf,Root=nil;
  read(n),read(m);
  Root=build(n);
  while(m--)
  {
    scanf("%s",opt);
    if(opt[0]!='M'||opt[2]!='X')
    read(a),read(b);
    if(opt[0]=='I')insert(a,b);
    else if(opt[0]=='D')del(a,b);
    else if(opt[0]=='M')
    {
      if(opt[2]=='K')read(c),make_same(a,b,c);
      else write(Root->maxsum),putchar(10);
    }
    else if(opt[0]=='R')reverse(a,b);
    else write(get_sum(a,b)),putchar(10);
  }
}

注:比實現較差,常數優化的不好的Splay跑得快

猜你喜欢

转载自blog.csdn.net/assass_cannotin/article/details/79313901