// 嘘探索解 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using pint = pair; #define FOR(i, begin, end) for(int i=(begin),i##_end_=(end);i=i##_begin_;i--) #define REP(i, n) FOR(i,0,n) #define IREP(i, n) IFOR(i,0,n) template bool chmax(T &m, const T q) { return m < q ? (m = q, true) : false; } template bool chmin(T &m, const T q) { return m > q ? (m = q, true) : false; } // UnionFind Tree (0-indexed), based on size of each disjoint set struct UnionFind { std::vector par, cou; UnionFind(int N = 0) : par(N), cou(N, 1) { iota(par.begin(), par.end(), 0); } int find(int x) { return (par[x] == x) ? x : (par[x] = find(par[x])); } bool unite(int x, int y) { x = find(x), y = find(y); if (x == y) return false; if (cou[x] < cou[y]) std::swap(x, y); par[y] = x, cou[x] += cou[y]; return true; } int count(int x) { return cou[find(x)]; } bool same(int x, int y) { return find(x) == find(y); } }; struct rand_int_ { using lint = long long; mt19937 mt; rand_int_() : mt(1837654) {} // fixed lint operator()(lint x) { return this->operator()(0, x); } // [0, x) lint operator()(lint l, lint r) { uniform_int_distribution d(l, r - 1); return d(mt); } } rnd; int main() { auto START = std::chrono::system_clock::now(); int64_t spent_ms = std::chrono::duration_cast(std::chrono::system_clock::now() - START).count(); int N, M; cin >> N >> M; vector> edges; REP(t, M) { int u, v, w; cin >> u >> v >> w; u--, v--, w--; edges.emplace_back(u, v, w); } vector ret1(M, 0); REP(ntry, 100) { vector ret(M); vector ufs(M, UnionFind(N)); REP(i, M) { auto [u, v, w] = edges[i]; if (chmax(ret[i], 1)) { UnionFind uf(N); uf.unite(u, v); uf.unite(u, w); ufs[i] = uf; } REP(j, i) { if (ufs[j].same(u, v)) continue; if (ufs[j].same(v, w)) continue; if (ufs[j].same(u, w)) continue; if (ret[j] < ret[i] - 1) continue; if (ret[j] == ret[i] - 1 and rnd(2)) continue; chmax(ret[i], ret[j] + 1); ufs[i] = ufs[j]; ufs[i].unite(u, v); ufs[i].unite(u, w); } } REP(i, M) chmax(ret1[i], ret[i]); } FOR(i, 1, ret1.size()) chmax(ret1[i], ret1[i - 1]); for (auto x : ret1) cout << x << '\n'; }