H 國是一個熱愛寫代碼的國家,那裏的人們很小去學校學習寫各類各樣的數據結構。伸展樹(splay)是一種數據
結構,由於代碼好寫,功能多,效率高,掌握這種數據結構成爲了 H 國的必修技能。有一天,邪惡的「卡」帶着
他的邪惡的「常數」來企圖毀滅 H 國。「卡」給 H 國的人洗腦說,splay 若是寫成單旋的,將會更快。「卡」稱
「單旋 splay」爲「spaly」。雖然說他說的很沒道理,但仍是有 H 國的人相信了,小 H 就是其中之一,spaly 馬
上成爲他的信仰。 而 H 國的國王,天然不容許這樣的風氣蔓延,國王構造了一組數據,數據由 m 個操做構成,
他知道這樣的數據確定打垮 spaly,可是國王還有不少不少其餘的事情要作,因此統計每一個操做所須要的實際代價
的任務就交給你啦。
數據中的操做分爲五種:
1. 插入操做:向當前非空 spaly 中插入一個關鍵碼爲 key 的新孤立節點。插入方法爲,先讓 key 和根比較,若是
key 比根小,則往左子樹走,不然往右子樹走,如此反覆,直到某個時刻,key 比當前子樹根 x 小,而 x 的左子
樹爲空,那就讓 key 成爲 x 的左孩子; 或者 key 比當前子樹根 x 大,而 x 的右子樹爲空,那就讓 key 成爲
x 的右孩子。該操做的代價爲:插入後,key 的深度。特別地,若樹爲空,則直接讓新節點成爲一個單個節點的樹
。(各節點關鍵碼互不相等。對於「深度」的解釋見末尾對 spaly 的描述)。
2. 單旋最小值:將 spaly 中關鍵碼最小的元素 xmin 單旋到根。操做代價爲:單旋前 xmin 的深度。
(對於單旋操做的解釋見末尾對 spaly 的描述)。
3. 單旋最大值:將 spaly 中關鍵碼最大的元素 xmax 單旋到根。操做代價爲:單旋前 xmax 的深度。
4. 單旋刪除最小值:先執行 2 號操做,而後把根刪除。因爲 2 號操做以後,根沒有左子樹,因此直接切斷根和右子
樹的聯繫便可(具體見樣例解釋)。 操做代價同 2 號操 做。
5. 單旋刪除最大值:先執行 3 號操做,而後把根刪除。 操做代價同 3 號操做。
對於不是 H 國的人,你可能須要瞭解一些 spaly 的知識,才能完成國王的任務:
a. spaly 是一棵二叉樹,知足對於任意一個節點 x,它若是有左孩子 lx,那麼 lx 的關鍵碼小於 x 的關鍵碼。
若是有右孩子 rx,那麼 rx 的關鍵碼大於 x 的關鍵碼。
b. 一個節點在 spaly 的深度定義爲:從根節點到該節點的路徑上一共有多少個節點(包括本身)。
c. 單旋操做是對於一棵樹上的節點 x 來講的。一開始,設 f 爲 x 在樹上的父親。若是 x 爲 f 的左孩子,那麼
執行 zig(x) 操做(如上圖中,左邊的樹通過 zig(x) 變爲了右邊的樹),不然執行 zag(x) 操做(在上圖中,將
右邊的樹通過 zag(f) 就變成了左邊的樹)。每當執 行一次 zig(x) 或者 zag(x),x 的深度減少 1,如此反覆,
直到 x 爲根。總之,單旋 x 就是經過反覆執行 zig 和 zag 將 x 變爲根。
把根刪除,就是其它節點深度所有-1.學習
那麼如今就要支持如下操做:在序列中間插入一個數、區間加減、單點修改、單點查詢、以及尋找第一個(或最後一個)比某值小的數。這題沒有強制在線,能夠用線段樹解決。若是在線能夠打splayspa
至於如何維護就很麻煩了···線段樹的左右區間爲離散化後的鍵值,用tr,mx,mi分別表示鍵值區間內深度最小值,鍵值區間內鍵值最大的點的深度··鍵值區間內鍵值最小的點的深度,前一個用於求每一個點的再spaly中的father,後兩個用於求前驅後繼··(具體見代碼)blog
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=100005;
int tr[N*4],mx[N*4],mi[N*4],tag[N*4],cnt[N*4],b[N],now,a[N],tot,m,n,op[N],deep;
inline int R()
{
char c;int f=0;
for(c=getchar();c<'0'||c>'9';c=getchar());
for(;c<='9'&&c>='0';c=getchar())
f=(f<<3)+(f<<1)+c-'0';
return f;
}
inline void lsh()
{
sort(b+1,b+n+1);
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+n+1,a[i])-b;
}
inline void update(int k)
{
if(cnt[k*2]) mi[k]=mi[k*2];else mi[k]=mi[k*2+1];
if(cnt[k*2+1]) mx[k]=mx[k*2+1];else mx[k]=mx[k*2];
tr[k]=min(tr[k*2],tr[k*2+1]);cnt[k]=cnt[k*2]+cnt[k*2+1];
}
inline void pushdown(int k)
{
if(tag[k])
{
if(cnt[k*2])
tag[k*2]+=tag[k],mi[k*2]+=tag[k],mx[k*2]+=tag[k],tr[k*2]+=tag[k];
if(cnt[k*2+1])
tag[k*2+1]+=tag[k],mi[k*2+1]+=tag[k],mx[k*2+1]+=tag[k],tr[k*2+1]+=tag[k];
tag[k]=0;
}
}
inline int pre(int k,int l,int r,int v)
{
if(r==v)
return mx[k];
int mid=(l+r)/2;
pushdown(k);
if(v<=mid) return pre(k*2,l,mid,v);
int t=pre(k*2+1,mid+1,r,v);
if(t) return t;
else return mx[k*2];
}
inline int nxt(int k,int l,int r,int v)
{
if(l==v)
return mi[k];
int mid=(l+r)/2;
pushdown(k);
if(v>mid) return nxt(k*2+1,mid+1,r,v);
int t=nxt(k*2,l,mid,v);
if(t) return t;
else return mi[k*2+1];
}
inline int getmin(int k,int l,int r)
{
if(l==r)
{
deep=tr[k];return l;
}
pushdown(k);
int mid=(l+r)/2;
if(cnt[k*2]) return getmin(k*2,l,mid);
else return getmin(k*2+1,mid+1,r);
}
inline int getmax(int k,int l,int r)
{
if(l==r)
{
deep=tr[k];return l;
}
pushdown(k);
int mid=(l+r)/2;
if(cnt[k*2+1]) return getmax(k*2+1,mid+1,r);
else return getmax(k*2,l,mid);
}
inline void insert(int k,int l,int r,int dep,int v)
{
if(l==r)
{
tr[k]=mx[k]=mi[k]=dep;cnt[k]=1;return;
}
pushdown(k);
int mid=(l+r)/2;
if(v<=mid) insert(k*2,l,mid,dep,v);
else insert(k*2+1,mid+1,r,dep,v);
update(k);
}
inline void Delete(int k,int l,int r,int v)
{
if(l==r)
{
tr[k]=n,mx[k]=mi[k]=cnt[k]=0;return;
}
pushdown(k);
int mid=(l+r)/2;
if(v<=mid) Delete(k*2,l,mid,v);
else Delete(k*2+1,mid+1,r,v);
update(k);
}
inline int find1(int k,int l,int r,int dep)
{
if(l==r) return l;
pushdown(k);
int mid=(l+r)/2;
if(cnt[k*2]&&tr[k*2]<dep) return find1(k*2,l,mid,dep);
return find1(k*2+1,mid+1,r,dep);
}
inline int find2(int k,int l,int r,int dep)
{
if(l==r) return l;
pushdown(k);
int mid=(l+r)/2;
if(cnt[k*2+1]&&tr[k*2+1]<dep) return find2(k*2+1,mid+1,r,dep);
return find2(k*2,l,mid,dep);
}
inline void modify(int k,int l,int r,int x,int y,int v)
{
if(!cnt[k]) return;
if(l>=x&&r<=y)
{
tr[k]+=v,mx[k]+=v,mi[k]+=v,tag[k]+=v;
return;
}
pushdown(k);
int mid=(l+r)/2;
if(x<=mid) modify(k*2,l,mid,x,y,v);
if(y>mid) modify(k*2+1,mid+1,r,x,y,v);
update(k);
}
int main()
{
//freopen("a.in","r",stdin);
m=R();
for(int i=1;i<=m;i++)
{
op[i]=R();
if(op[i]==1) a[++n]=R(),b[n]=a[n];
}
lsh();n++;memset(tr,0x3f3f3f3f,sizeof(tr));
for(int i=1;i<=m;i++)
{
if(op[i]==1)
{
now++;
insert(1,0,n,deep=max(pre(1,0,n,a[now]),nxt(1,0,n,a[now]))+1,a[now]);
}
else if(op[i]==2||op[i]==4)
{
int q=getmin(1,0,n),p;
Delete(1,0,n,q);p=find1(1,0,n,deep);modify(1,0,n,p,n,1);
if(op[i]==2) insert(1,0,n,1,q);else modify(1,0,n,0,n,-1);
}
else
{
int q=getmax(1,0,n),p;
Delete(1,0,n,q);p=find2(1,0,n,deep);modify(1,0,n,0,p,1);
if(op[i]==3) insert(1,0,n,1,q);else modify(1,0,n,0,n,-1);
}
printf("%d\n",deep);
}
return 0;
}