HDU 5764 After a Sleepless Night【DFS】

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5764

题意:

给定一棵$n$个结点的树,每个结点有个初始值,这些初始值构成$[1,n]$的排列,每个结点的新值为子树中所有结点初始值的最大值,先给定每个结点的新值,问是否存在这样的树。
数据范围:$1 \le n \le 100000$

分析:

官方题解讲的很清楚
具体过程就是先沿着新值为$n$的链$dfs$一遍找到$id$最小的根,然后再$dfs$一遍判断各个链是否有交叉,同时确定链最低点的值,剩下的值和剩下的点贪心的配对,每个点$u$的初始值范围为$[1,a[u]]$,从大往小枚举值,选择$id$最大的位置放入,用个优先级队列即可实现。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*************************************************************************
> File Name: 5764.cpp
> Author: jiangyuzhu
> Mail: 834138558@qq.com
> Created Time: 2016/9/30 12:57:02
************************************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 1e5 + 5, maxm= 20, oo = 0x3f3f3f3f;
struct EDGE{
int next, to;
}edge[maxn * 2 + 5];
int tot;
int head[maxn];
int used[maxn];
int a[maxn];
int ori[maxn];
int n;
vector<int>ve[maxn];
void init()
{
memset(ori, 0, sizeof(ori));
memset(used, 0, sizeof(used));
memset(head, -1, sizeof(head));
tot = 0;
for(int i = 1; i <= n; ++i) ve[i].clear();
}
void addedge(int from, int to)
{
edge[tot].to = to;
edge[tot].next = head[from];
head[from] = tot++;
}
int root;
void getroot(int u, int pa)
{
int cnt = 0;
bool flag = false;
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(v == pa) continue;
if(a[v] == n){
getroot(v, u);
flag = true;
}
}
if(!flag) root = min(root, u);
}
bool dfs(int u, int pa)
{
int maxx = 0;
int cnt = 0;
for(int i = head[u]; i != -1; i = edge[i].next){
int v = edge[i].to;
if(v == pa) continue;
if(!dfs(v, u)) return false;
maxx = max(maxx, a[v]);
if(a[v] == a[u]) cnt++;
}
if(a[u] < maxx) return false;
else if(a[u] == maxx && cnt != 1) return false;
else if(a[u] > maxx){
ori[u] = a[u];
if(used[a[u]]) return false;
used[a[u]] = u;
}
return true;
}
void solve()
{
scanf("%d", &n);
int u, v;
root = -1;
for(int i = 1; i <= n; ++i){
scanf("%d", &a[i]);
ve[a[i]].push_back(i);
if(a[i] == n) root = i;
}
for(int i = 1; i < n; ++i){
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
if(root == -1){
puts("Impossible");
return;
}
getroot(root, root);
if(!dfs(root, root)){
puts("Impossible");
return;
}
priority_queue<int>q;
for(int i = n; i >= 1; --i){
if(used[i]){
int sz = ve[i].size();
for(int j = 0; j < sz; ++j){
if(ve[i][j] == used[i]) continue;
q.push(ve[i][j]);
}
}else{
if(q.empty()){
puts("Impossible");
return;
}
int t = q.top();q.pop();
ori[t] = i;
}
}
for(int i = 1; i <= n; ++i) printf("%d%c", ori[i], i == n?'\n':' ');
return;
}
int main (void)
{
// freopen("1002.in", "r", stdin);
// freopen("my_1002.txt", "w", stdout);
int T;scanf("%d", &T);
for(int tt = 1; tt <= T; tt++){
printf("Case #%d: ", tt);
init();
solve();
}
return 0;
}
文章目录
  1. 1. 题目链接:
  2. 2. 题意:
  3. 3. 分析:
  4. 4. 代码: