CF 1467E Distinctive Roots in a Tree
阿新 • • 發佈:2021-01-20
- 給出一棵樹,結點有點權,求出樹上有多少個結點滿足從它開始的任何一條路徑點權不重複。
考慮每對權值相同的點,只有在它們之間範圍的點是可能成為答案的。
如果暴力列舉點對,即使可以 \(O(1)\) 打標記,複雜度也是 \(O(n^2)\) 的,考慮優化。
先將樹轉化為有根樹,對於一個點來說,
它處在的點對中另外一個節點可能在它的某棵子樹中或整個子樹外。
若在其子樹中,則需要對全域性除了該子樹打上標記。
否則,需要對整棵子樹打上那個標記。
這樣的話,每個結點最多修改兒子個數 + \(1\) 次,複雜度是線性的。
可以通過 \(dfs\) 序上差分來實現子樹修改。
可以在 \(dfs\) 的過程中開一個桶記錄每種顏色出現次數,前後做差即可得到子樹內部該種顏色的數目。
#include <bits/stdc++.h> #define rep(i, a, b) for (int i = (a); i <= (b); i++) #define per(i, a, b) for (int i = (a); i >= (b); i--) #define fi first #define se second using namespace std; typedef long long LL; typedef pair <int, int> P; const int inf = 0x3f3f3f3f, N = 3e5 + 10; template <typename T> void rd_(T &x) { x = 0; int f = 1; char ch = getchar(); for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1; for (; ch >= '0' && ch <= '9'; ch = getchar()) x = x*10 + ch - '0'; x *= f; } int n, h[N], cnt, a[N], tot, tim, ans, b[N], c[N], st[N], d[N], ed[N]; map <int, int> M; struct Edge { int to, next; } e[N<<1]; void add_(int u, int v) { e[++cnt] = (Edge) {v, h[u]}; h[u] = cnt; } void dfs_(int u, int fa = 0) { st[u] = ++tim; int last = b[a[u]], x; b[a[u]]++; for (int v, i = h[u]; i; i = e[i].next) { v = e[i].to; if (v == fa) continue; x = b[a[u]]; dfs_(v, u); if (x != b[a[u]]) d[1]++, d[st[v]]--, d[ed[v] + 1]++; } ed[u] = tim; if (b[a[u]] - last != c[a[u]]) d[st[u]]++, d[ed[u] + 1]--; } int main() { rd_(n); rep (i, 1, n) { rd_(a[i]); if (!M[a[i]]) M[a[i]] = ++tot; a[i] = M[a[i]], c[a[i]]++; } for (int u, v, i = 1; i < n; i++) { rd_(u), rd_(v); add_(u, v), add_(v, u); } dfs_(1); rep (i, 1, n) d[i] += d[i - 1], ans += d[i] == 0; printf("%d\n", ans); }