2171 D&F. Rae Taylor and Trees(easy & hard)
binary search, constructive algorithms, data structures, dp, dsu, greedy, implementation, 1600,
https://codeforces.com/contest/2171/problem/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.
这道题目分为 easy 和 hard 两个部分,对应 2171D 和 2171F 两题,这里直接展示 F。
【汤立祥、物理学院】思路:
第一步要看什么时候不能连成一颗树:
如果存在一个位置,将数组分为左右两部分,使得左侧的最小值大于右侧的最大值,那么无论如何都无法构造出满足要求的树,这时直接输出 "NO"。
第二步我们开始对能连成树的构造:
使用前缀最小值将序列划分成若干“根区间”,每个区间的第一个元素是当前前缀最小值。在每个区间内部,将该区间的根与后续元素连接;区间之间则通过下一个区间中最大的元素与当前根相连,得到一棵合法的树。
import sys
class TreeNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
input_data = list(map(int, sys.stdin.read().split()))
input_ptr = iter(input_data)
def solve():
n = next(input_ptr)
lst = [next(input_ptr) for _ in range(n)]
prefix_min = [0] * n
suffix_max = [0] * n
suffix_max_index = [0] * n
prefix_min[0] = lst[0]
suffix_max[-1] = lst[-1]
suffix_max_index[-1] = n-1
for i in range(1, n):
if prefix_min[i-1] > lst[i]:
prefix_min[i] = lst[i]
else:
prefix_min[i] = prefix_min[i-1]
for i in reversed(range(n-1)):
if suffix_max[i+1] < lst[i]:
suffix_max[i] = lst[i]
suffix_max_index[i] = i
else:
suffix_max[i] = suffix_max[i+1]
suffix_max_index[i] = suffix_max_index[i+1]
for i in range(n-1):
if prefix_min[i] > suffix_max[i+1]:
print("NO")
return
# little_prefix_min_block
prefix_min_block = []
res = ["YES"]
for i in range(n):
if prefix_min[i] == lst[i]:
prefix_min_block.append(i)
prefix_min_block.append(n)
for i in range(len(prefix_min_block)-1):
block_start = prefix_min_block[i]
block_end = prefix_min_block[i+1]
for end in range(block_start+1, block_end):
res.append(f"{lst[block_start]} {lst[end]}")
if i < len(prefix_min_block) - 2:
res.append(f"{lst[block_start]} {lst[suffix_max_index[block_end]]}")
print("\n".join(res))
def main():
t = next(input_ptr)
for _ in range(t):
solve()
if __name__ == "__main__":
main()