贪心 agc023F 01 on tree

https://agc023.contest.atcoder.jp/tasks/agc023_f

个人认为这题比E题好做多了好吧 我好废啊..

首先序列是有拓扑关系的

我们把序列看成若干个集合的合并

对于一个集合记\(C0, C1\)为集合中\(0, 1\)出现的次数

然后我们考虑一个集合\(u\) 以及他父亲的集合\(p\)

\(C0_u / C1_u\)最大时 把\(u\)放在\(p\)的后面 并将\(u, p\)合并

容易贪心证明是正确的

因为如果存在\(p\)的孩子\(w\)

最后的序列\(p, ..., u, ..., w\) 肯定没有\(p, ..., w, ..., u\)

不停的合并集合 用\(dsu\)维护就好了

找到最大的集合 写一个set

复杂度\(\mathcal O(n \log n)\)

#include <bits/stdc++.h>
#define int long long
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
  x = 0;char c = getchar(); bool f = 0;
  for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
  for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
  if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
  for(int i = 1; i <= n; i ++)
    cout << a[i] << " ";
  puts("");
}
const int N = 3e5 + 233;
int n, fa[N], pre[N], c[N][2], ans = 0, w[N];
inline int find(int x) {
  return pre[x] == x ? x : pre[x] = find(pre[x]);
}
struct Node {
  int id;
  bool operator < (const Node &rhs) const {
    int cu0 = c[id][0];
    int cu1 = c[id][1];
    int cv0 = c[rhs.id][0];
    int cv1 = c[rhs.id][1];
    return ((cu0 * cv1 > cv0 * cu1)
             || (cu0 * cv1 == cv0 * cu1 && id > rhs.id));
  }
};
set<Node> q;

main(void) {
  read(n);
  for(int i = 2; i <= n; i ++)
    read(fa[i]);
  for(int i = 1; i <= n; i ++)
    read(w[i]);
  for(int i = 1; i <= n; i ++) {
    pre[i] = i;
    c[i][w[i]] = 1;
  }
  for(int i = 2; i <= n; i ++)
    q.insert((Node) {i});
  for(int i = 1; i <= n - 1; i ++) {
    int u = q.begin()->id; q.erase(q.begin());
    int p = find(fa[u]); u = find(u); q.erase((Node) {p});
    ans += c[u][0] * c[p][1];
    c[p][1] += c[u][1]; c[p][0] += c[u][0];
    c[u][1] = 0; c[u][0] = 0;
    pre[u] = p;
    if(p != 1 && !q.count((Node) {p})) q.insert((Node) {p});
  }
  cout << ans << "\n";  
}

猜你喜欢

转载自www.cnblogs.com/foreverpiano/p/8996068.html