CF196 D2 D

Book of Evil,有一颗树,n个节点,有m个节点被标记,问n个节点中,有多少个节点,这些节点与这m个节点的最远的距离小于等于d。

用down[i], up[i]分别标记只考虑以i为root的子树的情况与这颗补集并上节点i的情况,两遍dfs,第一遍dfs求出down数组,第二遍求up数组,求up时,需要考虑当前节点i的父亲节点的up值以及节点i的兄弟节点的down值,然后取最大值。在求兄弟们的最大值时,由于所有的兄弟都会有这样的操作,因此可以先求出最大和次大,如果当前节点i的down值不是最大的,那么最大的一定在兄弟中,否则次大的一定是兄弟中最大的。

PS: 还个算法,可以先求出树中离得最远的两个带标记的节点,枚举树中的节点,若节点与这两个节点的距离小于等于d,则统计。

复制代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;

const int MAXN = 100005;
const int INF = 1e9;

int down[MAXN], up[MAXN];
int max1[MAXN], max2[MAXN];
bool p[MAXN];

vector<vector<int> > tree;

void dfs1(int u, int f) {
    down[u] = p[u] ? 0 : -INF;
    max1[u] = max2[u] = -INF;
    for (int i = 0; i < tree[u].size(); i++) {
        int v = tree[u][i];
        if (v != f) {
            dfs1(v, u);
            down[u] = max(down[u], down[v] + 1);
            if (down[v] > max1[u]) {
                max2[u] = max1[u];
                max1[u] = down[v];
            } else if (down[v] > max2[u]) {
                max2[u] = down[v];
            }
        }
    }
}

void dfs2(int u, int f) {
    up[u] = p[u] ? 0 : -INF;
    if (f != -1) {
        up[u] = max(up[u], up[f] + 1);
        int slide;
        if (down[u] < max1[f]) {
            slide = max1[f] + 2;
        } else {
            slide = max2[f] + 2;
        }
        up[u] = max(up[u], slide);
    }

    for (int i = 0; i < tree[u].size(); i++) {
        int v = tree[u][i];
        if (v != f) {
            dfs2(v, u);
        }
    }
}

int main() {
    int n, m, d;
    scanf("%d%d%d", &n, &m, &d);
    memset(p, false, sizeof(p));
    for (int i = 0; i < m; i++) {
        int t;
        scanf("%d", &t);
        p[t] = true;
    }
    tree.resize(n + 1);
    for (int i = 1; i < n; i++) {
        int a, b;
        scanf("%d%d", &a, &b);
        tree[a].push_back(b);
        tree[b].push_back(a);
    }

    dfs1(1, -1);
    dfs2(1, -1);

    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (max(down[i], up[i]) <= d) {
            ans++;
        }
    }
    
    printf("%d\n", ans);
}
复制代码

 

posted @   litstrong  阅读(601)  评论(0编辑  收藏  举报
努力加载评论中...
点击右上角即可分享
微信分享提示