传送门
先看
A
A
A序列,如果要让
A
A
A序列构成一棵树只需要将
A
A
A序列中的所有节点向在它前面的节点连边即可,不过这不能保证这棵树的
d
f
s
dfs
dfs序一定是
A
A
A序列,因此这里要用到一个小技巧,我们每次都向最后加的一条边的两个端点中的其中一个端点连边即可,这样一定能保证是
d
f
s
dfs
dfs序一定是
A
A
A序列,可以考虑用归纳法证明这一点,也可以随便验算几个例子,显然是正确的。
再看 B B B序列,我们发现只需要保证在遍历 B B B数组时每次连边都是当前节点向之前的节点连边就一定能够保证这颗树的拓扑序是 B B B序列,因为拓扑序的定义是儿子出现在祖先之后,每次向之前的节点连边意味着每个节点都能顺藤摸瓜直捣根节点,这个特点简单来说就是每个节点(除了第一个节点)都会有一条边连向位置更小的节点。
结合 A A A序列和 B B B序列各自需要满足的特性,我们发现只需要遍历 A A A序列,每次都让当前节点 u u u连向的节点 v v v满足 v v v或 u u u在B数组中的位置是当前遍历的所有点中最小的点(拓扑序性质) 以及 v v v是最后加上的一条边的一个端点。假设我们这次连上了 u − v u-v u−v这条边,那么比较一下 u u u, v v v节点在 B B B中谁位置更小,假设是 v v v节点,那么下次遇到 w w w节点我们自然地连接 w − v w-v w−v边,同理还需要比较 w w w和 v v v在 B B B数组中的位置大小来决定谁具有与下个节点连边的优先权,这样我们保证每次都是跟已遍历的节点中位置最小的节点相连接,由于 B B B数组中每个节点都被遍历到一遍,故每个节点都一定会跟位置比它小的节点相连接(除了第一个节点),满足拓扑序的性质,同时每次连接的点都是上次连接的边的某一个端点,满足 d f s dfs dfs序性质,故这种建树方式是可靠地。
此外我们还发现本题只会输出YES,因为这种建图方式显然没有反例存在。
int n,pos[maxn];
int main(){
n=rd();
FOR(i,1,n+1)pos[rd()]=i;
int b=rd(),pre=b;
wrsn("YES");
FOR(i,0,n-1){
b=rd();
wr(b),wrs(" "),wrn(pre);
if(!pre || pos[pre]>pos[b])pre=b;
}
}