Codeforces Round #695 (Div. 2) F. Strange Housing (树上差分)

F. Strange Housing

题意

给一棵 n n n 个节点的树,每个节点都有一个权值。统计有多少个满足以下要求的节点:从这个点出发的任意路径中,没有两个相同的权值出现在同一路径。

题解

很难直接求出满足要求的节点,但是我们可以标记不符合要求的点。

  • 如果遍历到点 u u u ,并且在 a [ u ] a[u] a[u] 没有全部出现在以 u u u 为根的子树中,那么 u u u 的子树都不满足,因为一定有一条路径经过 u u u 和另一个权值等于 a [ u ] a[u] a[u] 的点。
  • 如果遍历到点 u u u ,并且在以 u u u 为根的子树中也有一个点 v v v 的权值为 a [ v ] = a [ u ] a[v]=a[u] a[v]=a[u] ,那么那个 v v v 的子树不满足,并且除了包含点 v v v u u u 的子树,其他点也都不可取。
  • 把权值离散化然后树上差分即可。

代码

#pragma region
#include <algorithm>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
#pragma endregion
const int maxn = 2e5 + 5;
int n, a[maxn], b[maxn], c[maxn];
vector<int> g[maxn];
int dfn[maxn], nowid = 0, sz[maxn];
int sum[maxn], cnt[maxn];
void upd(int l, int r, int val) {
    
    
    if (l > r) return;
    c[l] += val, c[r + 1] -= val;
}
void dfs(int u, int f) {
    
    
    dfn[u] = ++nowid, sz[u] = 1;
    int tmp1 = cnt[a[u]];
    ++cnt[a[u]];
    for (auto v : g[u]) {
    
    
        if (v == f) continue;
        int tmp2 = cnt[a[u]];
        dfs(v, u);
        sz[u] += sz[v];
        if (cnt[a[u]] > tmp2) {
    
    
            upd(1, dfn[v] - 1, 1);
            upd(dfn[v] + sz[v], n, 1);
        }
    }
    tmp1 = cnt[a[u]] - tmp1;
    if (tmp1 < sum[a[u]]) upd(dfn[u], dfn[u] + sz[u] - 1, 1);
}
int main() {
    
    
    scanf("%d", &n);
    rep(i, 1, n) scanf("%d", &a[i]), b[i] = a[i];
    sort(b + 1, b + 1 + n);
    rep(i, 1, n) {
    
    
        a[i] = lower_bound(b + 1, b + 1 + n, a[i]) - b;
        sum[a[i]]++;
    }
    rep(i, 1, n - 1) {
    
    
        int u, v;
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 0);
    int ans = 0;
    rep(i, 1, n) {
    
    
        c[i] += c[i - 1];
        if (!c[i]) ++ans;
    }
    printf("%d\n", ans);
}

猜你喜欢

转载自blog.csdn.net/weixin_43860866/article/details/112711579