#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> ii;
const int INF = 1e9;
const ll LINF = 1e18;
const int N = 1e5 + 5;
const int M = 1e5 + 5;
const int MAX_W = 1e6 + 5;
// Đây là một bài ý tưởng tuy đơn giản nhưng cài đặt lại khá phức tạp
// Đầu tiên ta nhóm các cạnh có cùng trọng số lại chung một nhóm
// sau đó duyệt qua từng nhóm cạnh tăng dần theo trọng số
// Khi xét đến nhóm cạnh có trọng số = w, gọi T là MST (T có thể là rừng) đã dựng được trước đó (dùng các cạnh có trong các nhóm cạnh từ 1 đến w - 1):
// Để đơn giản thì mỗi thành phần liên thông (cây) trong T ta sẽ coi như một đỉnh
// Xét các cạnh e có trong nhóm cạnh hiện tại:
// - Nếu e nối giữa 2 đỉnh u, v đã chung TLPT thì ta kết luận ngay e là "none"
// - Ngược lại ta thêm e vào đồ thị
// - Lưu ý đồ thị được xét dưới dạng mỗi thành phần liên thông là một đỉnh, nên khi thêm thì ta sẽ thêm cạnh (findSet(u), findSet(v))
// Sau khi dựng đồ thị, có thể chứng minh được rằng những cạnh e là cầu thì đáp án sẽ là "any", còn ngược lại sẽ là "at least one"
struct Edge {
int u, v, idx;
};
struct dsu {
int n;
vector<int> p, sz;
dsu(int n): n(n) {
p.resize(n);
sz.resize(n);
for (int u = 0; u < n; u++) {
p[u] = u;
sz[u] = 1;
}
}
int findSet(int u) {
if (p[u] == u) return u;
return p[u] = findSet(p[u]);
}
void unionSet(int u, int v) {
u = findSet(u);
v = findSet(v);
if (u == v) return;
if (sz[u] < sz[v]) swap(u, v);
p[v] = u;
sz[u] += sz[v];
}
};
int n, m;
vector<Edge> edges[MAX_W];
vector<ii> adj[N];
int tin[N], low[N], timer;
bool is_bridge[M];
void dfs(int u, int p) {
tin[u] = low[u] = ++timer;
bool parent_skipped = true;
for (ii e : adj[u]) {
int v = e.first, idx = e.second;
if (v == p && parent_skipped) {
parent_skipped = false;
continue;
}
if (!tin[v]) {
dfs(v, u);
low[u] = min(low[u], low[v]);
if (low[v] > tin[u]) is_bridge[idx] = true;
}
else {
low[u] = min(low[u], tin[v]);
}
}
}
int ans[M]; // 0: "none", 1: "at least one", 2: "any"
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m;
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
edges[w].push_back({u, v, i});
}
memset(ans, -1, sizeof ans);
dsu DSU(n + 1);
for (int w = 1; w < MAX_W; w++) {
// Những cạnh e nối giữa 2 đỉnh u, v chung thành phần liên thông thì ta kết luận được ngay e là "none"
// Ngược lại thêm e vào đồ thị
for (Edge e : edges[w]) {
int u = DSU.findSet(e.u), v = DSU.findSet(e.v), idx = e.idx;
if (u == v) {
ans[idx] = 0;
}
else {
adj[u].push_back({v, idx});
adj[v].push_back({u, idx});
}
}
// Dùng kiến thức liên quan đến cây dfs để xác định các cạnh cầu
// Lưu ý đồ thị có thể có nhiều đỉnh nhưng lại rất ít cạnh
// Nên cần duyệt một cách khôn khéo, cụ thể ta sẽ duyệt theo cạnh
// Lưu ý thêm nữa đồ thị lúc này có thể là đa đồ thị (giữa 2 đỉnh có thể có nhiều cạnh nối)
timer = 0;
for (Edge e : edges[w]) {
int u = DSU.findSet(e.u), v = DSU.findSet(e.v), idx = e.idx;
if (ans[idx] == -1) {
if (!tin[u]) dfs(u, -1);
if (!tin[v]) dfs(v, -1);
}
}
// Chốt đáp án cũng như reset lại thông tin cho lần duyệt nhóm cạnh tiếp theo
for (Edge e : edges[w]) {
int u = DSU.findSet(e.u), v = DSU.findSet(e.v), idx = e.idx;
if (ans[idx] == -1) {
ans[idx] = (is_bridge[idx]) ? 2 : 1;
tin[u] = low[u] = 0;
tin[v] = low[v] = 0;
adj[u].clear();
adj[v].clear();
}
}
// Khi đã xác định được đáp án cho các cạnh có trong nhóm cạnh hiện tại rồi
// thì ta mới thêm các cạnh vào cây MST T
for (Edge e : edges[w]) {
int u = e.u, v = e.v;
DSU.unionSet(u, v);
}
}
for (int i = 0; i < m; i++) {
if (ans[i] == 0) cout << "none";
if (ans[i] == 1) cout << "at least one";
if (ans[i] == 2) cout << "any";
cout << '\n';
}
}
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+IAoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsgIAoKdHlwZWRlZiBsb25nIGxvbmcgbGw7ICAKdHlwZWRlZiBwYWlyPGludCwgaW50PiBpaTsgIAoKY29uc3QgaW50IElORiA9IDFlOTsgIApjb25zdCBsbCBMSU5GID0gMWUxODsgIAoKY29uc3QgaW50IE4gPSAxZTUgKyA1OyAKY29uc3QgaW50IE0gPSAxZTUgKyA1OyAKY29uc3QgaW50IE1BWF9XID0gMWU2ICsgNTsgCgovLyDEkMOieSBsw6AgbeG7mXQgYsOgaSDDvSB0xrDhu59uZyB0dXkgxJHGoW4gZ2nhuqNuIG5oxrBuZyBjw6BpIMSR4bq3dCBs4bqhaSBraMOhIHBo4bupYyB04bqhcAovLyDEkOG6p3UgdGnDqm4gdGEgbmjDs20gY8OhYyBj4bqhbmggY8OzIGPDuW5nIHRy4buNbmcgc+G7kSBs4bqhaSBjaHVuZyBt4buZdCBuaMOzbQovLyBzYXUgxJHDsyBkdXnhu4d0IHF1YSB04burbmcgbmjDs20gY+G6oW5oIHTEg25nIGThuqduIHRoZW8gdHLhu41uZyBz4buRCi8vIEtoaSB4w6l0IMSR4bq/biBuaMOzbSBj4bqhbmggY8OzIHRy4buNbmcgc+G7kSA9IHcsIGfhu41pIFQgbMOgIE1TVCAoVCBjw7MgdGjhu4MgbMOgIHLhu6tuZykgxJHDoyBk4buxbmcgxJHGsOG7o2MgdHLGsOG7m2MgxJHDsyAoZMO5bmcgY8OhYyBj4bqhbmggY8OzIHRyb25nIGPDoWMgbmjDs20gY+G6oW5oIHThu6sgMSDEkeG6v24gdyAtIDEpOgovLyDEkOG7gyDEkcahbiBnaeG6o24gdGjDrCBt4buXaSB0aMOgbmggcGjhuqduIGxpw6puIHRow7RuZyAoY8OieSkgdHJvbmcgVCB0YSBz4bq9IGNvaSBuaMawIG3hu5l0IMSR4buJbmgKLy8gWMOpdCBjw6FjIGPhuqFuaCBlIGPDsyB0cm9uZyBuaMOzbSBj4bqhbmggaGnhu4duIHThuqFpOgovLyAtIE7hur91IGUgbuG7kWkgZ2nhu69hIDIgxJHhu4luaCB1LCB2IMSRw6MgY2h1bmcgVExQVCB0aMOsIHRhIGvhur90IGx14bqtbiBuZ2F5IGUgbMOgICJub25lIgovLyAtIE5nxrDhu6NjIGzhuqFpIHRhIHRow6ptIGUgdsOgbyDEkeG7kyB0aOG7iwovLyAtIEzGsHUgw70gxJHhu5MgdGjhu4sgxJHGsOG7o2MgeMOpdCBkxrDhu5tpIGThuqFuZyBt4buXaSB0aMOgbmggcGjhuqduIGxpw6puIHRow7RuZyBsw6AgbeG7mXQgxJHhu4luaCwgbsOqbiBraGkgdGjDqm0gdGjDrCB0YSBz4bq9IHRow6ptIGPhuqFuaCAoZmluZFNldCh1KSwgZmluZFNldCh2KSkKLy8gU2F1IGtoaSBk4buxbmcgxJHhu5MgdGjhu4ssIGPDsyB0aOG7gyBjaOG7qW5nIG1pbmggxJHGsOG7o2MgcuG6sW5nIG5o4buvbmcgY+G6oW5oIGUgbMOgIGPhuqd1IHRow6wgxJHDoXAgw6FuIHPhur0gbMOgICJhbnkiLCBjw7JuIG5nxrDhu6NjIGzhuqFpIHPhur0gbMOgICJhdCBsZWFzdCBvbmUiCnN0cnVjdCBFZGdlIHsKCWludCB1LCB2LCBpZHg7ICAJCn07IAoKc3RydWN0IGRzdSB7CglpbnQgbjsgCgl2ZWN0b3I8aW50PiBwLCBzejsgIAoKCWRzdShpbnQgbik6IG4obikgewoJCXAucmVzaXplKG4pOyAgCgkJc3oucmVzaXplKG4pOyAgIAoJCWZvciAoaW50IHUgPSAwOyB1IDwgbjsgdSsrKSB7CgkJCXBbdV0gPSB1OyAgCgkJCXN6W3VdID0gMTsgCgkJfQoJfQoKCWludCBmaW5kU2V0KGludCB1KSB7CgkJaWYgKHBbdV0gPT0gdSkgcmV0dXJuIHU7ICAgCgkJcmV0dXJuIHBbdV0gPSBmaW5kU2V0KHBbdV0pOyAKCX0KCgl2b2lkIHVuaW9uU2V0KGludCB1LCBpbnQgdikgewoJCXUgPSBmaW5kU2V0KHUpOyAgCgkJdiA9IGZpbmRTZXQodik7ICAgCgkJaWYgKHUgPT0gdikgcmV0dXJuOwoJCWlmIChzelt1XSA8IHN6W3ZdKSBzd2FwKHUsIHYpOyAgCgkJcFt2XSA9IHU7IAoJCXN6W3VdICs9IHN6W3ZdOyAKCX0KfTsgCgppbnQgbiwgbTsgIAp2ZWN0b3I8RWRnZT4gZWRnZXNbTUFYX1ddOyAKCnZlY3RvcjxpaT4gYWRqW05dOyAKaW50IHRpbltOXSwgbG93W05dLCB0aW1lcjsgIApib29sIGlzX2JyaWRnZVtNXTsgICAKCnZvaWQgZGZzKGludCB1LCBpbnQgcCkgewoJdGluW3VdID0gbG93W3VdID0gKyt0aW1lcjsgICAgCgoJYm9vbCBwYXJlbnRfc2tpcHBlZCA9IHRydWU7IAoJZm9yIChpaSBlIDogYWRqW3VdKSB7CgkJaW50IHYgPSBlLmZpcnN0LCBpZHggPSBlLnNlY29uZDsgIAoJCWlmICh2ID09IHAgJiYgcGFyZW50X3NraXBwZWQpIHsKCQkJcGFyZW50X3NraXBwZWQgPSBmYWxzZTsgCgkJCWNvbnRpbnVlOwoJCX0KCQlpZiAoIXRpblt2XSkgewoJCQlkZnModiwgdSk7ICAgIAoJCQlsb3dbdV0gPSBtaW4obG93W3VdLCBsb3dbdl0pOyAKCQkJaWYgKGxvd1t2XSA+IHRpblt1XSkgaXNfYnJpZGdlW2lkeF0gPSB0cnVlOyAKCQl9CgkJZWxzZSB7CgkJCWxvd1t1XSA9IG1pbihsb3dbdV0sIHRpblt2XSk7IAoJCX0KCX0KfQoKaW50IGFuc1tNXTsgLy8gMDogIm5vbmUiLCAxOiAiYXQgbGVhc3Qgb25lIiwgMjogImFueSIKCmludCBtYWluKCkgewoJaW9zOjpzeW5jX3dpdGhfc3RkaW8oZmFsc2UpOyAKCWNpbi50aWUobnVsbHB0cik7IAkKCWNpbiA+PiBuID4+IG07IAoKCWZvciAoaW50IGkgPSAwOyBpIDwgbTsgaSsrKSB7CgkJaW50IHUsIHYsIHc7IAoJCWNpbiA+PiB1ID4+IHYgPj4gdzsgCgkJZWRnZXNbd10ucHVzaF9iYWNrKHt1LCB2LCBpfSk7IAoJfQoKCW1lbXNldChhbnMsIC0xLCBzaXplb2YgYW5zKTsgIAoKCWRzdSBEU1UobiArIDEpOyAKCWZvciAoaW50IHcgPSAxOyB3IDwgTUFYX1c7IHcrKykgewoJCS8vIE5o4buvbmcgY+G6oW5oIGUgbuG7kWkgZ2nhu69hIDIgxJHhu4luaCB1LCB2IGNodW5nIHRow6BuaCBwaOG6p24gbGnDqm4gdGjDtG5nIHRow6wgdGEga+G6v3QgbHXhuq1uIMSRxrDhu6NjIG5nYXkgZSBsw6AgIm5vbmUiCgkJLy8gTmfGsOG7o2MgbOG6oWkgdGjDqm0gZSB2w6BvIMSR4buTIHRo4buLIAoJCWZvciAoRWRnZSBlIDogZWRnZXNbd10pIHsKCQkJaW50IHUgPSBEU1UuZmluZFNldChlLnUpLCB2ID0gRFNVLmZpbmRTZXQoZS52KSwgaWR4ID0gZS5pZHg7ICAKCQkJaWYgKHUgPT0gdikgewoJCQkJYW5zW2lkeF0gPSAwOyAgCgkJCX0KCQkJZWxzZSB7CgkJCQlhZGpbdV0ucHVzaF9iYWNrKHt2LCBpZHh9KTsgIAoJCQkJYWRqW3ZdLnB1c2hfYmFjayh7dSwgaWR4fSk7IAoJCQl9CgkJfQoKCQkvLyBEw7luZyBraeG6v24gdGjhu6ljIGxpw6puIHF1YW4gxJHhur9uIGPDonkgZGZzIMSR4buDIHjDoWMgxJHhu4tuaCBjw6FjIGPhuqFuaCBj4bqndQoJCS8vIEzGsHUgw70gxJHhu5MgdGjhu4sgY8OzIHRo4buDIGPDsyBuaGnhu4F1IMSR4buJbmggbmjGsG5nIGzhuqFpIHLhuqV0IMOtdCBj4bqhbmgKCQkvLyBOw6puIGPhuqduIGR1eeG7h3QgbeG7mXQgY8OhY2gga2jDtG4ga2jDqW8sIGPhu6UgdGjhu4MgdGEgc+G6vSBkdXnhu4d0IHRoZW8gY+G6oW5oCgkJLy8gTMawdSDDvSB0aMOqbSBu4buvYSDEkeG7kyB0aOG7iyBsw7pjIG7DoHkgY8OzIHRo4buDIGzDoCDEkWEgxJHhu5MgdGjhu4sgKGdp4buvYSAyIMSR4buJbmggY8OzIHRo4buDIGPDsyBuaGnhu4F1IGPhuqFuaCBu4buRaSkKCQl0aW1lciA9IDA7IAoJCWZvciAoRWRnZSBlIDogZWRnZXNbd10pIHsKCQkJaW50IHUgPSBEU1UuZmluZFNldChlLnUpLCB2ID0gRFNVLmZpbmRTZXQoZS52KSwgaWR4ID0gZS5pZHg7ICAKCQkJaWYgKGFuc1tpZHhdID09IC0xKSB7IAoJCQkJaWYgKCF0aW5bdV0pIGRmcyh1LCAtMSk7IAoJCQkJaWYgKCF0aW5bdl0pIGRmcyh2LCAtMSk7IAoJCQl9CgkJfQoKCQkvLyBDaOG7kXQgxJHDoXAgw6FuIGPFqW5nIG5oxrAgcmVzZXQgbOG6oWkgdGjDtG5nIHRpbiBjaG8gbOG6p24gZHV54buHdCBuaMOzbSBj4bqhbmggdGnhur9wIHRoZW8KCQlmb3IgKEVkZ2UgZSA6IGVkZ2VzW3ddKSB7CgkJCWludCB1ID0gRFNVLmZpbmRTZXQoZS51KSwgdiA9IERTVS5maW5kU2V0KGUudiksIGlkeCA9IGUuaWR4OyAgCgkJCWlmIChhbnNbaWR4XSA9PSAtMSkgewoJCQkJYW5zW2lkeF0gPSAoaXNfYnJpZGdlW2lkeF0pID8gMiA6IDE7ICAgCgkJCQl0aW5bdV0gPSBsb3dbdV0gPSAwOyAgIAoJCQkJdGluW3ZdID0gbG93W3ZdID0gMDsgIAoJCQkJYWRqW3VdLmNsZWFyKCk7ICAKCQkJCWFkalt2XS5jbGVhcigpOyAgIAoJCQl9CgkJfQoKCQkvLyBLaGkgxJHDoyB4w6FjIMSR4buLbmggxJHGsOG7o2MgxJHDoXAgw6FuIGNobyBjw6FjIGPhuqFuaCBjw7MgdHJvbmcgbmjDs20gY+G6oW5oIGhp4buHbiB04bqhaSBy4buTaSAKCQkvLyB0aMOsIHRhIG3hu5tpIHRow6ptIGPDoWMgY+G6oW5oIHbDoG8gY8OieSBNU1QgVCAKCQlmb3IgKEVkZ2UgZSA6IGVkZ2VzW3ddKSB7CgkJCWludCB1ID0gZS51LCB2ID0gZS52OyAgCgkJCURTVS51bmlvblNldCh1LCB2KTsgCgkJfQoJfQoKCWZvciAoaW50IGkgPSAwOyBpIDwgbTsgaSsrKSB7CgkJaWYgKGFuc1tpXSA9PSAwKSBjb3V0IDw8ICJub25lIjsgCgkJaWYgKGFuc1tpXSA9PSAxKSBjb3V0IDw8ICJhdCBsZWFzdCBvbmUiOyAKCQlpZiAoYW5zW2ldID09IDIpIGNvdXQgPDwgImFueSI7CgkJY291dCA8PCAnXG4nOyAKCX0KfQ==