2171F. Rae Taylor and Trees (hard version)
binary search,constructive algorithms,data structures,dp,dsu,greedy,implementation,trees,*1600
https://codeforces.com/problemset/problem/2171/F
"To think a commoner would even fathom sitting next to me. Know your place!"
— Claire François
This is the hard version of the problem. The only difference between the easy and hard versions is that the hard version asks you to construct an example of a satisfactory tree.
As an Earth mage, Rae has mastered the spell of growing trees! But Manaria brags that she can grow a more impressive species of trees. Rae remembers that the most rare type of tree can be grown using a formula represented by a certain permutation — please help her construct it!
You are given a permutation∗ 𝑝 of length 𝑛.
Determine if there exists an undirected tree with 𝑛 vertices labeled 1,2,…,𝑛, satisfying the following condition:
- Let 𝑢 and 𝑣 (1≤𝑢<𝑣≤𝑛) be any two vertices connected by an edge. Then 𝑢 appears before 𝑣 in 𝑝.
Additionally, if there exists such a tree, output any of them.
∗A permutation of length 𝑛 is an array that contains every integer from 1 to 𝑛 exactly once, in any order.
Input
The first line contains a single integer 𝑡 (1≤𝑡≤104) — the number of test cases.
The first line of each test case contains a single integer 𝑛 (2≤𝑛≤2⋅105).
The second line of each test case contains 𝑛 integers, 𝑝1,𝑝2,…,𝑝𝑛 (1≤𝑝𝑖≤𝑛). It is guaranteed that all 𝑝𝑖 are distinct.
It is guaranteed that the sum of 𝑛 over all test cases does not exceed 2⋅105.
Output
For each test case, output on a single line "Yes" if there exists a tree satisfying the given condition, and "No" otherwise.
Then, if the answer is "Yes", output 𝑛−1 lines. The 𝑖-th of these lines should contain two integers 𝑢 and 𝑣, denoting an edge connecting vertices 𝑢 and 𝑣.
You may output the answer in any case (upper or lower). For example, the strings "yEs", "yes", "YES", and "yeS" will be recognized as "Yes".
Example
Input
9
6
1 3 4 5 2 6
4
3 4 1 2
5
4 3 5 1 2
4
1 2 3 4
7
4 3 5 7 6 2 1
6
2 4 6 1 3 5
3
2 1 3
4
2 4 1 3
6
4 2 6 5 1 3Output
Yes
3 1
4 1
6 5
6 2
6 1
No
No
Yes
2 1
4 3
4 1
No
Yes
4 2
6 2
3 1
5 1
5 2
Yes
3 2
3 1
Yes
4 2
3 1
3 2
Yes
6 4
6 2
3 1
5 4
2 3Note
In the first example, we can construct the tree given in the sample output. We have that
- 1<3, and 1 appears before 3 in 𝑝,
- 1<4, and 1 appears before 4 in 𝑝,
- 5<6, and 5 appears before 6 in 𝑝,
- 2<6, and 2 appears before 6 in 𝑝,
- 1<6, and 1 appears before 6 in 𝑝.
In the second example, it can be shown that there does not exist a tree satisfying the given constraints.
【尹显齐 25物理学院】有了上一问的经验,这个题就很简单了。只用把上一问连接的边都收集起来,然后构造一棵树即可。
class UnionFind:
def __init__(self,n):
self.p = list(range(n))
self.rank = [0]*n
def find(self,x):
if self.p[x] != x:
self.p[x] = self.find(self.p[x])
return self.p[x]
def union(self,x,y):
rx,ry = self.find(x),self.find(y)
if rx == ry:
return False
if self.rank[rx] < self.rank[ry]:
self.p[rx] = ry
elif self.rank[rx] > self.rank[ry]:
self.p[ry] = rx
else:
self.p[ry] = rx
self.rank[rx] += 1
return True
def judge(self,x,y):
return self.find(x) == self.find(y)
for _ in range(int(input())):
n = int(input())
arr = list(map(int,input().split()))
mins = [arr[0]]
for i in range(1,n):
mins.append(min(arr[i],mins[-1]))
maxs = [arr[-1]]
for i in range(n-2,-1,-1):
maxs.append(max(arr[i],maxs[-1]))
maxs = maxs[::-1]
uf = UnionFind(n)
edges = set()
if maxs[1] > arr[0]:
uf.union(maxs[1]-1,arr[0]-1)
edges.add((maxs[1]-1,arr[0]-1))
for i in range(1,n-1):
for j in range(1,i+1):
if mins[i-j] > arr[i]:
break
if not uf.judge(mins[i-j]-1,arr[i]-1):
uf.union(mins[i-j]-1,arr[i]-1)
edges.add((mins[i-j]-1,arr[i]-1))
break
if maxs[i+1] > arr[i]:
uf.union(maxs[i+1]-1,arr[i]-1)
edges.add((maxs[i+1]-1,arr[i]-1))
for j in range(1,n):
if mins[n-1-j] > arr[n-1]:
break
if not uf.judge(mins[n-1-j]-1,arr[n-1]-1):
uf.union(mins[n-1-j]-1,arr[n-1]-1)
edges.add((mins[n-1-j]-1,arr[n-1]-1))
break
ans = 1
# 判断是否是连通图
for i in range(1,n):
if not uf.judge(0,i):
ans = 0
break
print("YES" if ans else "NO")
if ans:
uf1 = UnionFind(n)
edges = list(edges)# 所有连接的边
for x,y in edges:
if not uf1.judge(x,y):# 如果两个端点还没有联通
uf1.union(x,y)
print(x+1,y+1)# 连接它们