第17届黑龙江省赛C
题目大意
一个树有n个节点,如果对于一个节点t,把所有点分到两个集合A、B中,并满足以下条件:
1、对于任意的u 、 v属于A,如果u位于t到v的路径上,则必须满足 a u a_u au < a v a_v av
2、对于任意的u 、 v属于B,如果u位于t到v的路径上,则必须满足 a u a_u au > a v a_v av
则节点t是有效的。
问:节点1是否有效
思路
一个贪心的思路:我要将节点放入A时,该节点是当前这条链上放入的最大的,并且之后放入的点要大于该点。所以同理,放入B集合中是最小的,而且越来越小。所以,基于贪心的思路,我们需要保证在放入A时,保证在B节点中的最小值尽量大,放入B时,保证A中节点最大值尽量小。考虑dp,dp[i][0]表示在i放入A中时,B集合中最小值的最大值,dp[i][1]表示放入B时,A中最大值的最小值。
如果tpos能放入A集合,那么pos节点子节点在B中最大值的最小值等于tpos节点的子节点在B中最大值的最小值
如果选择将tpos节点放入B集合,那么最大值将是a[tpos]
如果a[pos]的值比tpos子节点在A集合中的最大值要大,才能放入B集合,否则将不满足a[pos]是其子树在A中的最大值的条件
注意要把dp[i][0]初始化为负无穷,dp[i][1]为无穷。当我们发现dp[1][0]和dp[1][1]都不存在时,则表示节点1无效,否则有效。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int N = 1e5 + 5;
const int mod = 1e9 + 7;
const int INF = 0x7fffffff;
int n;
int a[N];
vector<int>e[N];
vector<int>son[N];
int dp[N][2];
int vis[N];
void preDFS(int pos) {
vis[pos] = 1;
for (auto i : e[pos]) {
if (vis[i])continue;
vis[i] = 1;
son[pos].push_back(i);
preDFS(i);
}
}
void dfs(int pos) {
// INF 表示不存在合法的情况
// dp[pos][0]表示pos在A集合时,其子节点在B的最大值的最小值的情况
for (auto tpos : son[pos]) {
dfs(tpos);
int t0 = INF;
int t1 = -INF;
//如果tpos能放入A集合,那么pos节点子节点在B中最大值的最小值等于tpos节点的子节点在B中最大值的最小值
if (a[pos] < a[tpos]) {
t0 = dp[tpos][0];
}
//如果选择将tpos节点放入B集合,那么最大值将是a[tpos]
//如果a[pos]的值比tpos子节点在A集合中的最大值要大,才能放入B集合,否则将不满足a[pos]是其子树在A中的最大值的条件
if (a[pos] < dp[tpos][1]) {
t0 = min(t0, a[tpos]);
}
dp[pos][0] = max(dp[pos][0], t0);
//下面如果pos在B集合同理
if (a[pos] > a[tpos]) {
t1 = dp[tpos][1];
}
if (a[pos] > dp[tpos][0]) {
t1 = max(t1, a[tpos]);
}
dp[pos][1] = min(dp[pos][1], t1);
}
}
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
dp[i][0] = -INF;
dp[i][1] = INF;
}
int u, v;
for (int i = 1; i < n; i++) {
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
preDFS(1);
bool flag = 0;
dfs(1);
flag = (dp[1][0] == INF) && (dp[1][1] == -INF);
if (!flag) {
cout << "YES" << endl;
}
else {
cout << "NO" << endl;
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
//cin >> t;
t = 1;
while (t--) {
solve();
}
return 0;
}