前言
Splay是會轉的的好,Treap是不會轉的妙,我們不用轉也能實現神奇的操作
在這裡比較複雜的是插入區間的操作,這是Treap沒有嘗試過的
如何 構造Treap?
Splay可以遞歸構造,但是Treap有key的問題,顯然不能那樣構造
那怎麼構造呢?
我們利用棧來解決這個問題
我們將每次構造出來的節點放到棧裏,當我們再次要構造一個新節點時,我們和棧頂節點比較,有兩種情況停止比較
- 棧頂元素key值的優先度高於新節點
- 棧空了
我們將最後一個彈出的節點接在新節點的左兒子上
如果棧未空,我們就將新節點接在棧頂的右兒子上
最後將新節點壓入棧
不要忘了將每個節點都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跑得快