#include #include #include using namespace std; #define MAXN 200000 #define MAXM 200000 int N, M; //Disjoint Find Union je implementováno přesně jako v kuchařce //v případě nejasností nahlédněte tam int parent[MAXN], rank[MAXN]; void init() { for (int i = 0; i < N; i++) { parent[i] = -1; rank[i] = 0; } } int root(int v) { if (parent[v] == -1) return v; parent[v] = root(parent[v]); return parent[v]; } bool find(int v, int w) { return (root(v) == root(w)); } //přejmenováno, union je klíčové slovo C++ void unite(int v, int w) { v = root(v); w = root(w); if (v == w) return; if (rank[v] == rank[w]) { parent[v] = w; rank[w]++; } else if (rank[v] < rank[w]) parent[v] = w; else parent[w] = v; } struct hrana { int a, b, w, id; bool operator<(const hrana& b) const { return w < b.w; } }; int vysledek[MAXM];//0-žádná,1-některá,2-každá hrana hrany[MAXM]; vector TE; //hrany dočasného grafu vector TV; //seznam vrcholů v dočasném grafu vector h_kam[MAXN]; //cílové vrcholy hran dočasného grafu vector h_id[MAXN]; //číslo této hrany pro rozlišení multihran int dostupna_hladina[MAXN]; //pole pro nalezení mostů, 0-nenavštíveno void najdi_mosty(int v, int rodic, int id_prichozi, int hladina) { if (dostupna_hladina[v] != 0) return; //zde jsme už byli dostupna_hladina[v] = hladina; for (int i = 0; i < h_kam[v].size(); i++) { if (h_id[v][i] != id_prichozi && h_kam[v][i] == rodic) //násobná hrana dostupna_hladina[v] = min(hladina-1,dostupna_hladina[v]); int w = h_kam[v][i]; if (dostupna_hladina[w] == 0) { //projdeme nenavštívený vrchol najdi_mosty(w, v, h_id[v][i], hladina+1); dostupna_hladina[v] = min(dostupna_hladina[v], dostupna_hladina[w]); //už poznáme, jestli je hrana vw mostem if (dostupna_hladina[w] > hladina) vysledek[h_id[v][i]] = 2; } else if (h_id[v][i] != id_prichozi) { //hranou, kterou jsme přišli, se již nesmíme vracet dostupna_hladina[v] = min(dostupna_hladina[v], dostupna_hladina[w]); } } } int main() { scanf("%d%d", &N, &M); //N počet vrcholů, M počet hran init(); for (int i = 0; i < M; i++) { scanf("%d%d%d", &hrany[i].a, &hrany[i].b, &hrany[i].w); hrany[i].id = i; } sort(hrany, hrany + M); for (int m = 0; m < M; m++) { hrana h = hrany[m]; if (m != 0 && h.w != hrany[m-1].w) { //v grafu jsou všechny hrany váhy hrany[m-1].w, //zpracujeme jej for (int i = 0; i < TV.size(); i++) najdi_mosty(TV[i], -1, -1, 2); //rozšíříme částečnou kostru for (int i = 0; i < TE.size(); i++) unite(TE[i].a, TE[i].b); //uklidíme graf for (int i = 0; i < TV.size(); i++) { h_kam[TV[i]].clear(); h_id[TV[i]].clear(); dostupna_hladina[TV[i]] = 0; } TE.clear(); TV.clear(); } if (find(h.a, h.b)) { vysledek[h.id] = 0; //v žádné kostře } else { vysledek[h.id] = 1; //už víme, že v alespoň některých kostrách //vložit do grafu h.a = root(h.a);//přejmenování vrcholů h.b = root(h.b); TE.push_back(h); TV.push_back(h.a); TV.push_back(h.b); h_kam[h.a].push_back(h.b); h_id[h.a].push_back(h.id); h_kam[h.b].push_back(h.a); h_id[h.b].push_back(h.id); } } for (int i = 0; i < TV.size(); i++) najdi_mosty(TV[i], -1, -1, 2); for (int i = 0; i < M; i++) { switch (vysledek[i]) { case 0: printf("žádná kostra\n"); break; case 1: printf("některá kostra\n"); break; case 2: printf("každá kostra\n"); break; } } return 0; }