第17届黑龙江省赛C

第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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值