「POI2014」MRO-Ant colony 题解

主要思路

如果你正确理解了题意,那么就不难想到用\(O(n)\)的 DFS 求出每一个叶子结点的上下界(然后我就没想了)。二分区间上的两个端点来获得总长度即可。

代码

// P3576.cpp
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int MAX_N = 1e6 + 200;

int head[MAX_N], current, n, m, k, deg[MAX_N], ptx, pty;
ll min_rg[MAX_N], max_rg[MAX_N], fa[MAX_N], gi[MAX_N];

struct edge
{
    int to, nxt;
} edges[MAX_N << 1];

void addpath(int src, int dst)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    head[src] = current++;
}

void dfs(int u)
{
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        if (edges[i].to != fa[u])
            fa[edges[i].to] = u, deg[u]++;
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        if (edges[i].to != fa[u])
        {
            min_rg[edges[i].to] = min_rg[u] * deg[u];
            max_rg[edges[i].to] = (max_rg[u] + 1) * deg[u] - 1;
            max_rg[edges[i].to] = min(max_rg[edges[i].to], gi[m]);
            if (min_rg[edges[i].to] <= gi[m])
                dfs(edges[i].to);
        }
}

ll binary_find(ll limit)
{
    int l = 1, r = m, ans = 0;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (gi[mid] < limit)
            ans = max(ans, mid), l = mid + 1;
        else
            r = mid - 1;
    }
    return ans;
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d%d", &n, &m, &k);
    for (int i = 1; i <= m; i++)
        scanf("%lld", &gi[i]);
    scanf("%d%d", &ptx, &pty);
    for (int i = 1, u, v; i <= n - 2; i++)
        scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u);
    sort(gi + 1, gi + 1 + m);
    min_rg[ptx] = max_rg[ptx] = min_rg[pty] = max_rg[pty] = k;
    dfs(ptx), dfs(pty);
    ll ans = 0;
    for (int i = 1; i <= n; i++)
        if (deg[i] == 0)
            ans += binary_find(max_rg[i] + 1) - binary_find(min_rg[i]);
    printf("%lld", ans * k);
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *