// compile: make data
// run: ./data < data.in
#include <bits/stdc++.h>
using namespace std;
#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,bmi,bmi2,lzcnt,popcnt")
#ifdef LOCAL
#include <debug/codeforces.h>
#define debug(x...) _debug_print(#x, x);
#else
#define debug(x...) {};
#endif
template<typename...Args> void print_(Args...args){((cout<<args<<" "),...)<<endl;}
#define rep(i,a,b) for(int i=(a);i<(int)(b);++i)
#define sz(v) ((int)(v).size())
#define print(...) print_(__VA_ARGS__);
#define INTMAX (int)(9223372036854775807)
#define INF (int)(1152921504606846976)
#define double long double
#define int long long
#define MAXN 200010
void download(int id) {
int n; cin >> n;
vector<int> u(n), v(n);
rep(i, 0, n-1) cin >> u[i] >> v[i];
if (id != 239) return;
cout << n << endl;
rep(i, 0, n-1) cout << u[i] << " " << v[i] << "#";
cout << endl;
}
namespace tree {
int n, root;
vector<int> parent, deg, hard;
vector<vector<int>> child;
vector<vector<pair<int, int>>> e;
void init(int ROOT=0) {
root = ROOT;
parent.assign(n, -1);
child.assign(n, vector<int>());
deg.assign(n, 0);
hard.assign(n, 0);
e.assign(n, vector<pair<int, int>>());
parent[ROOT] = -1;
}
void add_edge(int u, int v, int id) {
e[u].push_back({v, id});
e[v].push_back({u, -1});
}
void build() {
vector<bool> vis(n, 0);
queue<int> q;
q.push(root), vis[root] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
for (auto [v, _]: e[u]) {
if (!vis[v]) {
vis[v] = 1;
parent[v] = u;
child[u].push_back(v);
q.push(v);
}
}
}
rep(i, 0, n) deg[i] = sz(child[i]);
rep(i, 0, n) for (auto v: child[i]) hard[i] += deg[v] > 0;
}
void graphviz_dump(string filename = "graph.dot") {
ofstream gf;
gf.open(filename);
gf << "digraph {\n";
gf << " "; rep(i, 0, n) gf << i << " ;"[i==n-1]; gf << endl;
string notation = " -> ";
rep(i, 0, sz(child)) {
for (auto v: child[i]) {
gf << " " << i << notation << v << ";\n";
}
}
gf << "}\n";
}
}
int search(vector<pair<int, int>> &a, int l, int r, int x) {
int ans = -1;
while (l <= r) {
int mid = l + (r-l) / 2;
if (a[mid].first > x) r = mid - 1;
else ans = mid, l = mid + 1;
}
return ~ans ? a[ans].second : -1;
}
void solve() {
using namespace tree;
cin >> n;
init(0);
rep(i, 0, n-1) {
int u, v; cin >> u >> v;
add_edge(u - 1, v - 1, i + 1);
}
build();
graphviz_dump();
if (n % 3) {
cout << -1 << endl;
return;
}
queue<int> q;
rep(i, 0, n) {
if (deg[i] && !hard[i]) q.push(i);
}
vector<pair<int, int>> cut;
int cnt = 0;
while (!q.empty()) {
debug(q)
int u = q.front(); q.pop();
// debug(deg)
// debug(hard)
if (deg[u] > 2) break;
if (deg[u] == 2) {
int p = parent[u];
cnt += 3;
if (!~p) continue;
cut.push_back({p, u});
--deg[p], --hard[p];
if (~parent[p] && !deg[p]) --hard[parent[p]];
if (deg[p] && !hard[p]) q.push(p);
if (~parent[p] && deg[parent[p]]) q.push(parent[p]);
parent[u] = -1;
}
else if (deg[u] == 1) {
int p = parent[u];
if (!~p) break;
deg[p] = hard[p] = 1;
cnt += 3;
for (auto v: child[p]) if (v != u && ~parent[v]) parent[v] = -1, cut.push_back({p, v});
if (~parent[p]) {
int gp = parent[p];
cut.push_back({gp, p});
--deg[gp], --hard[gp];
parent[p] = -1;
if (deg[gp] && !hard[gp]) q.push(gp);
if (~parent[gp] && deg[parent[gp]] && !(--hard[parent[gp]])) q.push(parent[gp]);
}
}
}
if (cnt < n) {
cout << -1 << endl;
return;
}
// rep(i, 0, n) if (!valid[i]) {
// cout << -1 << endl;
// return;
// }
rep(i, 0, n) sort(e[i].begin(), e[i].end());
cout << sz(cut) << endl;
for (auto [u, v]: cut) {
int id = search(e[u], 0, sz(e[u]) - 1, v);
if (!~id) id = search(e[v], 0, sz(e[v]) - 1, u);
cout << id << " ";
}
cout << endl;
}
int32_t main() {
ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
int _; cin >> _;
rep(i, 1, _+1) {
solve();
// if (_ != 10000) solve();
// else download(i);
}
// while (_--) solve();
return 0;
}
No Comments