51nodP1771最小生成树的边
我们知道最小生成树能够替换的边一定是任意的最小生成树的最小值,所以我们将最小生成树中大小不是最小的边染成黑色,将是最小的边染成灰色,将非树边染成白色.于是我们只用考虑灰色边的情况.
我们先随意生成一颗最小生成树,将不在这颗树中的灰色边逐一加入,每一条边的加入都会形成一个环.找出环上灰色的边,将这些边都打上标记.
找环的过程也十分简单.
我们可以将最初生成的最小生成树中每一个点\(dfs\)一个深度\(deep\),对于每一条边\((x,y)\),我们可以采用向上暴跳找\(LCA\)的方式,易知环即为\(x\to lca\to y\to x\)
最后将没有标记的灰边染成白色。
#include<stdio.h>
#include<ctype.h>
#include<algorithm>
#define il inline
#define rg register
#define gi read<int>
using namespace std;
const int O = 1e5 + 10;
template<class TT>
il TT read() {
TT o = 0, fl = 1; char ch = getchar();
while (!isdigit(ch)) fl ^= ch == '-', ch = getchar();
while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
return fl ? o : -o;
}
struct Data {
int x, y, w, id;
bool tag;
il bool operator < (Data rhs) const {
return w < rhs.w;
}
}a[O];
struct Edge { int to, nt, id; }e[O << 1];
int n, m, cnt, head[O], fa[O], lst[O], ans[O], dep[O], f[O];
il int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }
il void add(int u, int v, int i) { e[++cnt] = (Edge){v, head[u], i}; head[u] = cnt; }
il void dfs(int u, int fa) {
dep[u] = dep[fa] + 1, f[u] = fa;
for (int i = head[u]; i; i = e[i].nt) {
int v = e[i].to;
if(v == fa) continue;
lst[v] = e[i].id;
dfs(v, u);
}
}
int main() {
n = gi(), m = gi();
for (int i = 1; i <= n; ++i) fa[i] = i;
for (int i = 1; i <= m; ++i) a[i] = (Data){gi(), gi(), gi(), i};
sort(a + 1, a + m + 1);
for (int i = 1; i <= m; ++i) {
int X = find(a[i].x), Y = find(a[i].y);
if(X == Y) continue;
fa[X] = Y;
a[i].tag = 1;
add(a[i].x, a[i].y, i); add(a[i].y, a[i].x, i);
}
for (int i = 1; i <= m; ++i)
if (a[i].tag) ans[a[i].id] = 2;
else ans[a[i].id] = 0;
dfs(1, 0);
for (int i = 1; i <= m; ++i) {
if (a[i].tag) continue;
ans[a[i].id] = 1;
bool flag = 1;
int x = a[i].x, y = a[i].y;
if (dep[x] < dep[y]) x ^= y ^= x ^= y;
for (; dep[x] > dep[y]; x = f[x])
if (a[i].w == a[lst[x]].w) ans[a[lst[x]].id] = 1, flag = 0;
for (; x != y; x = f[x], y = f[y]) {
if (a[i].w == a[lst[x]].w) ans[a[lst[x]].id] = 1, flag = 0;
if (a[i].w == a[lst[y]].w) ans[a[lst[y]].id] = 1, flag = 0;
}
if (flag) ans[a[i].id] = 0;
}
for (int i = 1; i <= m; ++i)
switch (ans[i]) {
case 0:puts("none");break;
case 1:puts("at least one");break;
default:puts("any");
}
return 0;
}