[POI2011]DYN-Dynamite

Face questions

Question is intended: to a tree, the tree has a number of key nodes, selected from the m points, these points so that the critical nodes maximum minimum distance minimum

Maximum minimum, half of decisive answers

We need only determines whether there are m possible to reach all points in the mid range of the key points

Violence: a look over the range from the mid point of each bfs whether to cover all the points, o (n ^ 2logn)

Can be found greedy, a key point is either point of management within its sub-tree, or be it outside the sub-tree management point, so we recorded a pair / struct

first to x is the root of the subtree No one key point of management farthest distance x, second represents the shortest distance to x is the root of the subtree selected point distance x.

①if (first + second <= mid) tree rooted at x can deal with their own

②if (first == mid) means that we must choose the point x

Since then up more than a point from mid, and this time forced to choose x at this point, and updates the first, second to

③if (this point is the key point && second> mid) will update the first

Special attention out of time to sentence 1 (roots)

#include <stdio.h>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <time.h>

#pragma warning(disable:4996)

template<typename T> T min(T x, T y)
{
    return x < y ? x : y;
}
template<typename T> T max(T x, T y)
{
    return x > y ? x : y;
}

const int MAXN = 300005;
const int B = 400;
const int INF = 2000000005;

struct node {
    int to;
    node *next;
};
void addnode(node *&head, int to)
{
    node *p = new node;
    p->to = to;
    p->next = head;
    head = p;
}

int N, M;
node *edge[MAXN];
int deep[MAXN], fa[MAXN][25], key[MAXN], cnt;
int rank[MAXN], st[MAXN * 2][25], len;
int f[MAXN], list[MAXN], num;
bool mark[MAXN];

bool cmp(const int u, const int v)
{
    return deep[u] > deep[v];
}

int anc(int x, int k)
{
    for (int i = 0; i < 25; i++)
        if (k&(1 << i))
            x = fa[x][i];
    return x;
}
int LCA(int x, int y)
{
    x = rank[x];
    y = rank[y];
    if (x > y)
        std::swap(x, y);
    int len = y - x + 1;
    int t = 0;
    while (1 << t <= len)
        t++;
    t--;
    y = y - (1 << t) + 1;
    return deep[st[x][t]] > deep[st[y][t]]? st[y][t] : st[x][t];
}
int dis(int x, int y)
{
    return deep[x] + deep[y] - 2 * deep[LCA(x, y)];
}

int nearest(int v)
{
    int x = f[v];
    for (int i = 1; i <= num; i++)
        x = min(x, dis(v, list[i]));
    return x;
}

void dfs1(int v)
{
    f[v] = mark[v]? 0: INF;
    for (node *p = edge[v]; p; p = p->next)
        if (p->to != fa[v][0])
        {
            dfs1(p->to);
            f[v] = min(f[v], f[p->to] + 1);
        }
}
void dfs2(int v)
{
    f[v] = min(f[v], f[fa[v][0]] + 1);
    for (node *p = edge[v]; p; p = p->next)
        if (p->to != fa[v][0])
            dfs2(p->to);
}

void insert(int v)
{
    list[++num] = v;
    if (num == B)
    {
        for (int i = 1; i <= num; i++)
            mark[list[i]] = true;
        dfs1(1);
        dfs2(1);
        num = 0;
    }
}

bool judge(int d)
{
    int i, n = 0;
    num = 0;
    memset(mark, 0, sizeof(mark));
    memset(f, 63, sizeof(f));

    for (i = 1; i <= cnt; i++)
    {
        if (nearest(key[i]) > d)
        {
            n++;
            insert(anc(key[i], min(d, deep[key[i]])));
        }
    }
    return n <= M;
}

void dfs(int v)
{
    st[++len][0] = v;
    rank[v] = len;
    for (int i = 1; i < 25; i++)
        fa[v][i] = fa[fa[v][i - 1]][i - 1];
    for (node *p = edge[v]; p; p = p->next)
        if (p->to != fa[v][0])
        {
            fa[p->to][0] = v;
            deep[p->to] = deep[v] + 1;
            dfs(p->to);
            st[++len][0] = v;
        }
}

void init()
{
    int i, j, u, v;

    scanf("%d %d", &N, &M);
    for (i = 1; i <= N; i++)
    {
        scanf("%d", &u);
        if (u)
            key[++cnt] = i;
    }
    for (i = 1; i < N; i++)
    {
        scanf("%d %d", &u, &v);
        addnode(edge[u], v);
        addnode(edge[v], u);
    }

    dfs(1);
    std::sort(key + 1, key + cnt + 1, cmp);

    deep[0] = INF;
    for (i = 1; i < 25; i++)
    {
        int r = min(1 << (i - 1), len);
        for (j = 1; j <= len; j++)
        {
            if (r < len)
                r++;
            st[j][i] = cmp(st[j][i - 1], st[r][i - 1]) ?
                st[r][i - 1] : st[j][i - 1];
        }
    }
}

int main()
{
    int l = -1, r = MAXN;

    init();
    while (r - l > 1)
    {
        int mid = (l + r) / 2;
        if (judge(mid))
            r = mid;
        else
            l = mid;
    }

    printf("%d\n", r);

    return 0;
}

  

Guess you like

Origin www.cnblogs.com/ainiyuling/p/11243934.html