CF246E Blood Cousins Return [dsu on tree 树上启发式合并]

同下面一题,用map记录就好了

#include <bits/stdc++.h>
using namespace std;
// int read() {
//  int x = 0;
//  char c = getchar();
//  while (c < 48) c = getchar();
//  while (c > 47) x = x * 10 + (c - 48), c = getchar();
//  return x;
//}

int n, q;
const int maxn = 2e5 + 52;
string s[maxn];
vector<int> g[maxn];
int dep[maxn], sz[maxn], son[maxn], fa[maxn];
void dfs(int u) {
  sz[u] = 1;
  for (int v : g[u]) {
    if (v == fa[u]) continue;
    fa[v] = u, dep[v] = dep[u] + 1;
    dfs(v);
    sz[u] += sz[v];
    if (sz[v] > sz[son[u]]) son[u] = v;
  }
}

int vis[maxn];
map<string, int> mp[maxn];
int sum[maxn];
void upd(string s, int dep, int qwq) {
  if (qwq == 1) {
    if (++mp[dep][s] == 1) ++sum[dep];
  } else {
    if (--mp[dep][s] == 0) --sum[dep];
  }
}
void add(int u, int qwq) {
  upd(s[u], dep[u], qwq);
  for (int v : g[u])
    if (!vis[v] && v ^ fa[u]) add(v, qwq);
}
vector<pair<int, int>> qr[maxn];
int ans[maxn];
void dfs(int u, int kep) {
  for (int v : g[u])
    if (v ^ fa[u] && v ^ son[u]) dfs(v, 0);
  if (son[u]) dfs(son[u], 1), vis[son[u]] = 1;
  add(u, 1);
  vis[son[u]] = 0;
  for (auto x : qr[u]) ans[x.second] = sum[x.first];
  if (!kep) add(u, -1);
}

int main() {
  ios ::sync_with_stdio(false);
  cin.tie(0), cout.tie(0);
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> s[i] >> fa[i];
    g[fa[i]].push_back(i);
  }
  for (int i = 1; i <= n; i++)
    if (!fa[i]) dfs(i);
  cin >> q;
  for (int i = 1; i <= q; i++) {
    int x, y;
    cin >> x >> y;
    qr[x].push_back({ dep[x] + y, i });
  }
  for (int i = 1; i <= n; i++)
    if (!fa[i]) dfs(i, 0);
  for (int i = 1; i <= q; i++) cout << ans[i] << '
';
  return 0;
}
原文地址:https://www.cnblogs.com/Isaunoya/p/12456792.html