HNOI2017 單旋
阿新 • • 發佈:2018-12-13
Link
Diffculty
演算法難度5,思維難度6,程式碼難度7
Description
給定一棵Spaly(不知道的可以去看官方題面),支援五種操作:
- 插入一個數x
- 單旋最小值
- 單旋最大值
- 單旋刪除最小值
- 單旋刪除最大值
每次操作之後輸出當前操作點的操作前深度,也就是操作代價。
,保證權值互不相同
Solution
我們通過模擬單旋操作可以發現,單旋最值不會對樹的結構造成大的影響。
我們可以通過set維護前驅後繼,這樣可以支援插入了。
單旋的時候需要修改深度,有時需要區間加,區間減,那麼我們維護一棵線段樹就可以了。
具體細節需要自己模擬之後大討論一波,還是比較考驗細節處理能力和程式碼功底的。
還有我們最好離散化權值,這樣便於操作。
可以做到 。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#define LL long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=' ';
while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9')x=x*10+(ch^48),ch=getchar();
return f==1?x:-x;
}
const int N=1e5+5;
set<int> s;
int n,m,root,a[N],opt[N],Hash[N];
int fa[N],ch[N][2];
int dep[N<<2];
inline void pushdown(int rt){
if(dep[rt]){
dep[rt<<1]+=dep[rt];
dep[rt<<1|1]+=dep[rt];
dep[rt]=0;
}
}
inline void modify_pos(int rt,int l,int r,int pos,int v){
if(l==r){
dep[rt]=v;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(pos<=mid)modify_pos(rt<<1,l,mid,pos,v);
else modify_pos(rt<<1|1,mid+1,r,pos,v);
}
inline void modify_seg(int rt,int l,int r,int L,int R,int v){
if(L>R)return;
if(L<=l && r<=R){
dep[rt]+=v;
return;
}
pushdown(rt);
int mid=(l+r)>>1;
if(L<=mid)modify_seg(rt<<1,l,mid,L,R,v);
if(mid+1<=R)modify_seg(rt<<1|1,mid+1,r,L,R,v);
}
inline int query(int rt,int l,int r,int pos){
if(l==r)return dep[rt];
pushdown(rt);
int mid=(l+r)>>1;
if(pos<=mid)return query(rt<<1,l,mid,pos);
else return query(rt<<1|1,mid+1,r,pos);
}
int main(){
m=read();
for(int i=1;i<=m;++i){
opt[i]=read();
if(opt[i]==1)a[i]=read(),Hash[++n]=a[i];
}
sort(Hash+1,Hash+n+1);
for(int i=1;i<=m;++i)if(a[i])a[i]=lower_bound(Hash+1,Hash+n+1,a[i])-Hash;
for(int i=1;i<=m;++i){
if(opt[i]==1){
if(!root){
root=a[i];
modify_pos(1,1,n,a[i],1);
s.insert(a[i]);
printf("1\n");
}
else{
s.insert(a[i]);
set<int>::iterator it=s.find(a[i]);
if(it!=s.begin()){
--it;
if(!ch[*it][1])ch[*it][1]=a[i],fa[a[i]]=*it;
++it;
}
if(!fa[a[i]]){
++it;
ch[*it][0]=a[i];fa[a[i]]=*it;
}
int dep=query(1,1,n,fa[a[i]])+1;
modify_pos(1,1,n,a[i],dep);
printf("%d\n",dep);
}
}
else if(opt[i]==2){
set<int>::iterator it=s.begin();
printf("%d\n",query(1,1,n,*it));
if(!fa[*it]){
continue;
}
int L=*it,R=fa[*it];
modify_seg(1,1,n,1,L,1);
modify_seg(1,1,n,R,n,1);
modify_pos(1,1,n,*it,1);
if(ch[*it][1]){
fa[ch[*it][1]]=fa[*it];
}
ch[fa[*it]][0]=ch[*it][1];
fa[root]=*it;
ch[*it][1]=root;
fa[*it]=0;
root=*it;
}
else if(opt[i]==3){
set<int>::iterator it=--s.end();
printf("%d\n",query(1,1,n,*it));
if(!fa[*it]){
continue;
}
int L=fa[*it],R=*it;
modify_seg(1,1,n,1,L,1);
modify_seg(1,1,n,R,n,1);
modify_pos(1,1,n,*it,1);
if(ch[*it][0]){
fa[ch[*it][0]]=fa[*it];
}
ch[fa[*it]][1]=ch[*it][0];
fa[root]=*it;
ch[*it][0]=root;
fa[*it]=0;
root=*it;
}
else if(opt[i]==4){
set<int>::iterator it=s.begin();
printf("%d\n",query(1,1,n,*it));
int L=*it,R=fa[*it];
if(!fa[*it])R=n+1;
if(ch[*it][1]){
modify_seg(1,1,n,L+1,R-1,-1);
fa[ch[*it][1]]=fa[*it];
}
if(!fa[*it]){
root=ch[*it][1];
s.erase(*it);
continue;
}
ch[fa[*it]][0]=ch[*it][1];
s.erase(*it);
}
else{
set<int>::iterator it=--s.end();
printf("%d\n",query(1,1,n,*it));
int L=fa[*it],R=*it;
if(!fa[*it])L=0;
if(ch[*it][0]){
modify_seg(1,1,n,L+1,R-1,-1);
fa[ch[*it][0]]=fa[*it];
}
if(!fa[*it]){
root=ch[*it][0];
s.erase(*it);
continue;
}
ch[fa[*it]][1]=ch[*it][0];
s.erase(*it);
}
}
return 0;
}