CF160D Edges in MST

题目大意

给定带权无向连通图(无重边,自环),对于每一条边:

  • 情况 11:一定在最小生成树上,输出 any

  • 情况 22:可能在某个最小生成树上,输出 at least one

  • 情况 33:一定不在最小生成树上,输出 none

解题思路

首先根据 Kruskal 找到任意一棵最小生成树。

考虑新加入一条未选中的边 (u,v)(u,v),边权记为 ll,那么必会形成一个环,由于最小生成树的特性,环上的边的权值不会大于 ll,若满足前面的性质,那么 (u,v)(u,v) 这条边即为情况 33

情况一,最小生成树上 (u,v)(u,v) 两端之间的路径上有一条边等于 ll,则将那条边替换为此边,仍为最小生成树,即那条边与此边均为情况 22

情况二,如果最小生成树上 (u,v)(u,v) 两端之间的路径上每条边都小于此边长,则该边为情况 33,因为不存在一种替换方案。

此外为情况 11

考虑树链剖分,维护树上路径中的最大边权,

做完最小生成树后,枚举每一条未被选中的边(边权记为 ll),求出最小生成树上此边两端之间的路径上的最大边权 maxlmaxl

如果是情况 33,那么就是 l>maxll>maxl

如果是情况 22,那么就是 l=maxll=maxl

考虑在情况 22 时,也要将树上路径中权值等于 ll 的边标记起来,使用线段树维护。

详见代码。

CODE

#include <bits/stdc++.h>

using namespace std;

struct edge
{
    int u, v, l, num;
    bool operator<(const edge a) const
    {
        return l < a.l;
    }
} e[100005];

int F[100005], n, m;

inline int getf(int k)
{
    return F[k] == k ? k : (F[k] = getf(F[k]));
}

struct node
{
    int to, next, l, no;
} g[300021];

int h[100005];

int tot = 0, cnt_node = 0;

int to[100005], from[100005], a[100005], type[100005], at[100005];

inline void add(int u, int v, int l, int no)
{
    tot++;
    g[tot].to = v;
    g[tot].next = h[u];
    g[tot].l = l;
    g[tot].no = no;
    h[u] = tot;
}

bool in[100005];

int siz[100005], son[100005], top[100005], d[100005], fa[100005];

inline void dfs1(int k, int f)
{
    siz[k] = 1;
    for (int i = h[k]; i; i = g[i].next)
    {
        int v = g[i].to;
        if (v == f)
            continue;
        d[v] = d[k] + 1;
        a[v] = g[i].l;
        at[v] = g[i].no;
        fa[v] = k;
        dfs1(v, k);
        siz[k] += siz[v];
        if (siz[v] > siz[son[k]])
            son[k] = v;
    }
}

inline void dfs2(int k, int fa)
{
    top[son[k]] = top[k];
    to[k] = ++cnt_node;
    from[cnt_node] = k;
    if (son[k] == 0)
        return;
    dfs2(son[k], k);
    for (int i = h[k]; i > 0; i = g[i].next)
    {
        int v = g[i].to;
        if (v == fa || v == son[k])
            continue;
        top[v] = v;
        dfs2(v, k);
    }
}

int f[400005];

bool tag[400005];

#define lc (k << 1)

#define rc (k << 1 | 1)

inline void build(int l, int r, int k)
{
    if (l == r)
    {
        f[k] = a[from[l]];
        return;
    }
    int mid = (l + r) >> 1, t = k << 1;
    build(l, mid, t);
    build(mid + 1, r, t | 1);
    f[k] = max(f[t], f[t | 1]);
}

inline int query(int l, int r, int l1, int r1, int k)
{
    if (l == l1 && r == r1)
        return f[k];
    int mid = (l + r) >> 1;
    if (r1 <= mid)
        return query(l, mid, l1, r1, lc);
    else if (l1 > mid)
        return query(mid + 1, r, l1, r1, rc);
    else
    {
        int t1 = query(l, mid, l1, mid, lc), t2 = query(mid + 1, r, mid + 1, r1, rc);
        return max(t1, t2);
    }
}

inline void update(int l, int r, int l1, int r1, int k, int t)
{
    if (f[k] < t)
        return;
    if (l == l1 && r == r1)
    {
        if (f[k] == t)
        {
            tag[k] = 1;
            return;
        }
        int mid = l + r >> 1;
        if (f[lc] >= t)
            update(l, mid, l, mid, lc, t);
        if (f[rc] >= t)
            update(mid + 1, r, mid + 1, r, rc, t);
        return;
    }
    int mid = l + r >> 1;
    if (r1 <= mid)
        update(l, mid, l1, r1, lc, t);
    else if (l1 > mid)
        update(mid + 1, r, l1, r1, rc, t);
    else
        update(l, mid, l1, mid, lc, t), update(mid + 1, r, mid + 1, r1, rc, t);
}

inline int querypath(int u, int v)
{
    int ans = 0;
    while (top[u] ^ top[v])
    {
        if (d[top[u]] < d[top[v]])
            u ^= v, v ^= u, u ^= v;
        ans = max(ans, query(1, n, to[top[u]], to[u], 1));
        u = fa[top[u]];
    }
    if (to[u] == to[v])
        return ans;
    if (to[u] > to[v])
        u ^= v, v ^= u, u ^= v;
    ans = max(ans, query(1, n, to[u] + 1, to[v], 1));
    return ans;
}

inline void updatepath(int u, int v, int cnt_node)
{
    int ans = 100000;
    while (top[u] ^ top[v])
    {
        if (d[top[u]] < d[top[v]])
            u ^= v, v ^= u, u ^= v;
        update(1, n, to[top[u]], to[u], 1, cnt_node);
        u = fa[top[u]];
    }
    if (to[u] == to[v])
        return;
    if (to[u] > to[v])
        u ^= v, v ^= u, u ^= v;
    update(1, n, to[u] + 1, to[v], 1, cnt_node);
}

inline void pushdown(int l, int r, int k)
{
    if (l == r)
    {
        if (tag[k])
            type[at[from[l]]] = 2;
        return;
    }
    if (tag[k])
    {
        if (f[lc] == f[k])
            tag[lc] = 1;
        if (f[rc] == f[k])
            tag[rc] = 1;
    }
    int mid = l + r >> 1;
    pushdown(l, mid, lc);
    pushdown(mid + 1, r, rc);
}

signed main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i++)
    {
        int u, v, l;
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].l);
        e[i].num = i;
    }
    sort(e + 1, e + 1 + m);
    for (int i = 1; i <= n; i++)
        F[i] = i;
    int k = 1, cnt_node = 0;
    while (cnt_node < n - 1)
    {
        int t1 = getf(e[k].u), t2 = getf(e[k].v);
        if (t1 != t2)
        {
            in[k] = 1;
            add(e[k].u, e[k].v, e[k].l, e[k].num);
            add(e[k].v, e[k].u, e[k].l, e[k].num);
            F[t1] = t2;
            cnt_node++;
        }
        k++;
    }
    fa[1] = top[1] = 1;
    dfs1(1, 0);
    dfs2(1, 0);
    build(1, n, 1);
    for (int i = 1; i <= m; i++)
    {
        type[e[i].num] = 1;
        if (!in[i])
        {
            int cnt_node = querypath(e[i].u, e[i].v);
            if (e[i].l > cnt_node)
                type[e[i].num] = 3;
            else
            {
                type[e[i].num] = 2;
                updatepath(e[i].u, e[i].v, cnt_node);
            }
        }
    }
    pushdown(1, n, 1);
    for (int i = 1; i <= m; i++)
        puts(type[i] == 1 ? "any" : (type[i] == 2 ? "at least one" : "none"));
    return 0;
}
posted @ 2021-11-22 22:02  蒟蒻orz  阅读(7)  评论(0编辑  收藏  举报  来源