Loading

AGC010F 题解

现在也就会写一写代码长度不超过 \(1k\) 的题目了。 /kk

看上去一脸不可做,看到 从必败状态逆推 的提示后会了。

考虑什么算是必败状态,我们设此时棋子所在的位置为 \(now\)
那么可以发现,当对于所有的 \(t\) 存在 \(now\rightarrow t\) 这条边,都满足 \(A_{now}\leq A_t\) 时,在 \(t\) 点一定是必败的。
原因显然,因为对于上述的情况,一但我把棋子从 \(now\) 移走,对手就会把它移回到 \(now\) 点,然后我就寄了。
我们考虑把眼光放低,着重去看一次移棋子的操作,容易发现当 \(A_{now}\leq A_t\) 时我把棋子从 \(now\) 移到 \(t\) 是不能做的。
原因是一样的,因为对手仍然可以把我赶回 \(now\)
所以可以看出你一条边是不可能从不同方向经过两次,也就是说在树中不能走回头路。

那我们直接令 \(i\) 为根节点,跑 \(n\)\(\text{DFS}\) ,复杂度 \(O(n^2)\)
代码只有 800B ,小学生写不出来的话幼儿园都会写。。。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>

#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)

const int N = 5005;

int n, a[N], flag[N];
std::vector <int> dis[N];

inline void dfs(int now, int father) {
  for (int t : dis[now]) {
    if (t == father) continue;
    dfs(t, now);
    if (flag[t] == 0 && a[now] > a[t]) 
      flag[now] = 1;
  }
}

signed main(void) {
  std::cin >> n;
  for (int i = 1; i <= n; i++) std::cin >> a[i];
  for (int i = 1, x, y; i < n; i++) {
    scanf("%d %d", &x, &y);
    dis[x].emplace_back(y);
    dis[y].emplace_back(x);
  }
  for (int i = 1; i <= n; i++) {
    memset(flag, 0, sizeof(flag));
    dfs(i, 0);
    if (flag[i] == 1)
      std::cout << i << " ";
  }
  std::cout << std::endl;
  return 0;
}
posted @ 2022-09-03 23:28  Aonynation  阅读(14)  评论(0编辑  收藏  举报