CF160D Edges in MST
题目大意
给定带权无向连通图(无重边,自环),对于每一条边:
-
情况 :一定在最小生成树上,输出
any
; -
情况 :可能在某个最小生成树上,输出
at least one
; -
情况 :一定不在最小生成树上,输出
none
。
解题思路
首先根据 Kruskal
找到任意一棵最小生成树。
考虑新加入一条未选中的边 ,边权记为 ,那么必会形成一个环,由于最小生成树的特性,环上的边的权值不会大于 ,若满足前面的性质,那么 这条边即为情况 。
情况一,最小生成树上 两端之间的路径上有一条边等于 ,则将那条边替换为此边,仍为最小生成树,即那条边与此边均为情况 。
情况二,如果最小生成树上 两端之间的路径上每条边都小于此边长,则该边为情况 ,因为不存在一种替换方案。
此外为情况 。
考虑树链剖分,维护树上路径中的最大边权,
做完最小生成树后,枚举每一条未被选中的边(边权记为 ),求出最小生成树上此边两端之间的路径上的最大边权 。
如果是情况 ,那么就是 。
如果是情况 ,那么就是 。
考虑在情况 时,也要将树上路径中权值等于 的边标记起来,使用线段树维护。
详见代码。
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;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122083