题目描述
Given two 1 ∼ n 1\sim n 1∼n permutations A , B A, B_{} A,B , you should construct an unrooted tree T T_{} T , which satisfies that A A_{} A is a possible topological order of T T_{} T if A 1 A_1 A1 is made the root, and that B B_{} B is a possible dfs order of T T_{} T if B 1 B_1 B1 is made the root.
Here, a permutation P P_{} P of size n n_{} n is a valid topological order of a rooted tree T T_{} T of size n n_{} n iff that for all edges in T T_{} T , the parent nodes are at front of the child nodes in permutation P P_{} P .
输入描述:
The first line contains one integer n ( 2 ≤ n ≤ 2 × 1 0 5 ) n~(2\le n\le 2\times 10^5) n (2≤n≤2×105), denoting the size of permutations.
The second line contains n n_{} n integers A 1 , A 2 , ⋯ , A n A_1, A_2, \cdots, A_n A1,A2,⋯,An , denoting permutation A A_{} A .
The third line contains n n_{} n integers B 1 , B 2 , ⋯ , B n B_1, B_2, \cdots, B_n B1,B2,⋯,Bn , denoting permutation B B_{} B .
输出描述:
If solution exists, print “YES” in one line, and following n − 1 n - 1_{} n−1 lines each contains two integers u , v ( 1 ≤ u , v ≤ n , u ≠ v ) u, v~(1\le u,v \le n, u\neq v) u,v (1≤u,v≤n,u=v), denoting one edge in T T_{} T . If multiple solutions exist, print any one of them. If no solution, print “NO” in one line.
输入
5
2 1 4 3 5
4 2 5 1 3
输出
YES
1 2
1 3
2 4
2 5
说明
思路一
从样例来举例子:
top: 2 1 4 3 5
dfs: 4 2 5 1 3
首先构造一个单枝树 4->2->5->1->3,肯定满足 d f s dfs dfs 序。但是它不满足 t o p top top 序,只能枚举 t o p top top 序的每一个前缀,依次调整 d f s dfs dfs 序,最终使得它同时满足 d f s dfs dfs 序与 t o p top top 序。
设一个 v i s vis vis 标记这是树上的一个分叉,最先标记 t o p [ 1 ] top[1] top[1] ,也就是 2 2 2 是树上的一个分叉( t o p top top 序的根节点)。然后,从 t o p [ 2 ] top[2] top[2] 到 t o p [ n ] top[n] top[n] ,每一个点,都与一个被标记为分叉,并且 d f s dfs dfs 序在当前点的前方,最近的一个点相连。若是它前放没有满足要求的点,那么找它 d f s dfs dfs 序后方,标记为分叉的最近的一个点,与它相连。
说的有些绕,代码如下。复杂度 O ( n l o g n ) O(n~log~n) O(n log n)。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,a[N],b[N],pos[N];
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i],pos[b[i]]=i;
cout<<"YES\n";
set<int> st;
st.insert(0),st.insert(n+1);
st.insert(pos[a[1]]);
for(int i=2;i<=n;i++){
auto ps=st.lower_bound(pos[a[i]]); ps--;
if(*ps==0) ps++;
cout<<a[i]<<" "<<b[*ps]<<"\n";
st.insert(pos[a[i]]);
}
}
STD
标准答案与前面的的方法很类似了:
top: 2 1 4 3 5
dfs: 4 2 5 1 3
首先根据 t o p top top 序构造一个单枝树 2->1->4->3->5,它肯定满足 t o p top top 序。但是它不满足 d f s dfs dfs 序,然后枚举 d f s dfs dfs 序的每一个前缀,依次调整 t o p top top 序,最终使得它同时满足 d f s dfs dfs 序与 t o p top top 序。
top序调整的时候,每一个结点可以与它前方的任意结点连边,而不破坏 top 序。有一种必定有解的策略是:每一个点,与最前方的满足条件的点相连,之后更新最前方满足要求的点。
说的依旧很迷惑。
复杂度 O ( n ) O(n) O(n)
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int n,a[N],b[N],pos[N];
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],pos[a[i]]=i;
for(int i=1;i<=n;i++) cin>>b[i];
cout<<"YES\n";
int pre=pos[b[1]];
for(int i=2;i<=n;i++){
cout<<b[i]<<" "<<a[pre]<<"\n";
pre=min(pre,pos[b[i]]);
}
}