LOJ传送门
洛谷传送门
解析:
其实仔细想一想,这道题其实需要支持的操作就是交换左右儿子和Splay里面的Rotate,然后求最小中序遍历。
显然Rotate是不会改变中序遍历的,重点其实就是交换左右儿子。
我们找到第一个度数小于三的点,显然它就是最优解中极左链的末端。
处理出以它为根的时候每个点子树中序遍历的最小开头。
然后贪心选择最小的那边,考虑一个作为父亲另一个作为右儿子的情况就行了。
我们在 g e t a n s getans getans里面决定父亲和右儿子,在 g e t o r i getori getori里面决定左儿子和右儿子,感觉写的还是比较好懂的?可以看一下代码。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
using std::cout;
using std::cerr;
cs int N=1e6+6;
int n;
int p[N][3],d[N];
int mn[N];
int st[N],top;
void dfs(int u,int fa){
int y=0,z=0;
for(int re i=0;i<d[u];++i)if(p[u][i]^fa)dfs(p[u][i],u),(y?z:y)=p[u][i];
if(y&&z)mn[u]=std::min(mn[y],mn[z]);
else if(y)mn[u]=std::min(u,mn[y]);
else mn[u]=u;
}
void get_ori(int u,int fa){
int y=0,z=0;
for(int re i=0;i<d[u];++i)if(p[u][i]^fa)(y?z:y)=p[u][i];
if(y&&z){
if(mn[y]>mn[z])std::swap(y,z);
get_ori(y,u),st[++top]=u,get_ori(z,u);
}
else if(y){
if(mn[u]==u)st[++top]=u,get_ori(y,u);
else get_ori(y,u),st[++top]=u;
}
else st[++top]=u;
}
void get_ans(int u,int fa){
st[++top]=u;
int y=0,z=0;
for(int re i=0;i<d[u];++i)if(p[u][i]^fa)(y?z:y)=p[u][i];
if(y&&z){
if(mn[y]>mn[z])std::swap(y,z);
get_ori(y,u),get_ans(z,u);
}
else if(y){
if(mn[y]<y)get_ori(y,u);
else get_ans(y,u);
}
}
signed main(){
std::ios::sync_with_stdio(false);
n=getint();
for(int re i=1;i<=n;++i)
for(int re j=(d[i]=getint())-1;~j;--j)p[i][j]=getint();
for(int re i=1;i<=n;++i)if(d[i]<3){
dfs(i,0);
get_ans(i,0);
for(int re i=1;i<=n;++i)cout<<st[i]<<" ";
break;
}
return 0;
}