洛谷3721 HNOI2017單旋(LCT+set+思維)
阿新 • • 發佈:2018-12-04
這題難道不是spaly裸題嗎?
言歸正傳QWQ
一看到這個題目,其實第一反應是很懵X的
從來沒有見過類似的題目啊,什麼 ,單旋。QWQ很懵逼啊
不過,我們可以注意到這麼一件事情,就是我們對於樹中元素移動的時候,只會移動
。
那麼會不會有什麼性質呢
QWQ
經過手玩,以
為慄,我們可以發現我們將這個點單旋到根的話,相當於就是說保持的原樹的形態不變,把
的左兒子連到
的父親,然後刪除這個點,然後把
接到
的左兒子上。
最小值和最大值同理
這不就是一個 和一個 嗎QWQ
所以直接可以上
每次代價,就是從當前點到根的距離
我們現在考慮怎麼插入
有一個結論是,插入的時候一定會插到前驅和後繼中深度比較大的那個的對應兒子。
因為因為前驅和後繼一定是父子關係,只有深的那個才可能出現合法位置的空兒子
QWQ另外的話就是一些細節了
需要除了 之外,再維護原樹的形態和 的兩個陣列
然後實時維護一個 ,表示原樹的根。每次操作完都 ,便於計算路徑長度
剩下的還是直接去看程式碼吧
QWQ
感覺這個題很好啊,思維挺不錯的
細節也有不少
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk makr_pair
#define ll long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 3e5+1e2;
struct Node
{
int opt,val;
};
Node a[maxn];
int ch[maxn][3];//LCT中的父子關係
int fa[maxn];
int zuzong[maxn];//spaly中的父子關係
int son[maxn][3];
int n,m;
int rev[maxn],st[maxn],size[maxn];
set<int> s;
int b[maxn];
int cnt;
int root;
int sson(int x)
{
if (ch[fa[x]][0]==x) return 0;
else return 1;
}
bool notroot(int x)
{
return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
}
void update(int x)
{
if (!x) return;
size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
void reverse(int x)
{
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
}
void pushdown(int x)
{
if(rev[x])
{
if (ch[x][0]) reverse(ch[x][0]);
if (ch[x][1]) reverse(ch[x][1]);
rev[x]=0;
}
}
void rotate(int x)
{
int y=fa[x],z=fa[y];
int b=sson(x),c=sson(y);
if (notroot(y)) ch[z][c]=x;
fa[x]=z;
ch[y][b]=ch[x][!b];
fa[ch[x][!b]]=y;
ch[x][!b]=y;
fa[y]=x;
update(y);
update(x);
}
void splay(int x)
{
int y=x,cnt=0;
st[++cnt]=y;
while (notroot(y)) y=fa[y],st[++cnt]=y;
while (cnt) pushdown(st[cnt--]);
while (notroot(x))
{
int y=fa[x],z=fa[y];
int b=sson(x),c=sson(y);
if (notroot(y))
{
if(b==c) rotate(y);
else rotate(x);
}
rotate(x);
//cout<<x<<endl;
}
update(x);
}
void access(int x)
{
for (int y=0;x;y=x,x=fa[x])
{
splay(x);
ch[x][1]=y;
update(x);
}
}
void makeroot(int x)
{
access(x);
splay(x);
reverse(x);
}
int findroot(int x)
{
access(x);
splay(x);
while (ch[x][0])
{
pushdown(x);
x=ch[x][0];
}
return x;
}
void split(int x,int y)
{
makeroot(x);
access(y);
splay(y);
}
void link(int x,int y)
{
if (!x || !y) return;
makeroot(x);
if (findroot(y)!=x)
fa[x]=y;
}
void cut(int x,int y)
{
if (!x || !y) return;
split(x,y);
if (ch[x][0] || ch[x][1] || fa[x]!=y || ch[y][1]) return;
fa[x]=ch[y][0]=0;
update(y);
}
int query(int x)
{
access(x);
splay(x);
return size[x];
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
{
a[i].opt=read();
if (a[i].opt==1) a[i].val=read(),b[++cnt]=a[i].val;
}
sort(b+1,b+1+cnt);
for (int i=1;i<=n;i++)
if(a[i].opt==1) a[i].val=lower_bound(b+1,b+1+cnt,a[i].val)-b; //離散化,權值既是編號
for (int i=1;i<=n;i++)
{
if (a[i].opt==1)
{
int lyf,ymh=0;
if (s.size()==0)
{
cout<<1<<"\n";
s.insert(a[i].val);
root=a[i].val;
continue;
}
set<int> :: iterator now = s.upper_bound(a[i].val);
if(now!=s.end())
{
//ymh=max(ymh,query(*now));
if (query(*now)>=ymh) ymh=query(*now),lyf=*now;
}
if(now!=s.begin())
{
--now;
if (query(*now)>=ymh) ymh=query(*now),lyf=*now;
}
//插入的時候,應該找到前驅和後繼深度較深的那個,然後插入
//因為前驅和後繼一定是父子關係,只有深的那個 才可能出現合法位置的空兒子
cout<<ymh+1<<"\n";
zuzong[a[i].val]=lyf;
son[lyf][lyf<a[i].val]=a[i].val;
s.insert(a[i].val);
link(a[i].val,lyf);
}
if (a[i].opt==2)
{
int now = *(s.begin());
int faa = zuzong[now];
int ss = son[now][1];
cout<<query(now)<<"\n";
if (now==root) continue;
cut(now,faa);
cut(now,ss);
link(ss,faa);
link(root,now);
zuzong[root]=now;
zuzong[now]=0;
son[now][1]=root;
zuzong[ss]=faa;
son[faa][0]=ss;
root=now;
//找到最小值,然後手動修改原樹的父子關係,然後暴力link和cut
}
if (a[i].opt==3)
{
int now = *(s.rbegin());
int faa = zuzong[now];
int ss = son[now][0];
cout<<query(now)<<"\n";
if (now==root) continue;
cut(now,faa);
cut(now,ss);
link(ss,faa);
link(root,now);
zuzong[root]=now;
zuzong[now]=0;
son[now][0]=root;
zuzong[ss]=faa;
son[faa][1]=ss;
root=now;
//和最小值同理
}
if(a[i].opt==4)
{
set<int> :: iterator pos = s.begin();
int now = *(s.begin());
int faa = zuzong[now];
int ss = son[now][1];
cout<<query(now)<<"\n";
cut(now,faa);
cut(now,ss);
link(ss,faa);
zuzong[ss]=faa;
son[faa][0]=ss;
son[now][0]=son[now][1<