| #include <iostream> |
| #include <vector> |
| #include <algorithm> |
| #include <queue> |
|
|
| using namespace std; |
|
|
| |
| struct Edge { |
| int u, v, id; |
| }; |
|
|
| int n; |
| vector<int> p; |
| vector<vector<pair<int, int>>> adj; |
| vector<Edge> edge_list; |
| vector<vector<int>> dists; |
|
|
| |
| struct DP_Res { |
| long long val0; |
| long long val1; |
| int child_for_1; |
| }; |
|
|
| vector<DP_Res> memo; |
| vector<int> weights; |
|
|
| |
| void bfs(int start, vector<int>& d) { |
| fill(d.begin(), d.end(), -1); |
| d[start] = 0; |
| queue<int> q; |
| q.push(start); |
| while (!q.empty()) { |
| int u = q.front(); |
| q.pop(); |
| for (auto& edge : adj[u]) { |
| int v = edge.first; |
| if (d[v] == -1) { |
| d[v] = d[u] + 1; |
| q.push(v); |
| } |
| } |
| } |
| } |
|
|
| |
| void dfs_dp(int u, int parent) { |
| long long sum_max = 0; |
| |
| for (auto& edge : adj[u]) { |
| int v = edge.first; |
| if (v == parent) continue; |
| dfs_dp(v, u); |
| sum_max += max(memo[v].val0, memo[v].val1); |
| } |
| |
| |
| memo[u].val0 = sum_max; |
| |
| |
| long long best_val1 = -1e18; |
| int best_child = -1; |
| bool has_child = false; |
| |
| for (auto& edge : adj[u]) { |
| int v = edge.first; |
| int idx = edge.second; |
| if (v == parent) continue; |
| has_child = true; |
| |
| |
| |
| |
| long long current_val = weights[idx] + memo[v].val0 + (sum_max - max(memo[v].val0, memo[v].val1)); |
| if (current_val > best_val1) { |
| best_val1 = current_val; |
| best_child = v; |
| } |
| } |
| |
| if (has_child) { |
| memo[u].val1 = best_val1; |
| memo[u].child_for_1 = best_child; |
| } else { |
| memo[u].val1 = -1e18; |
| } |
| } |
|
|
| |
| void get_matching(int u, int parent, bool matched_with_parent, vector<int>& matching_edges) { |
| if (matched_with_parent) { |
| |
| for (auto& edge : adj[u]) { |
| int v = edge.first; |
| if (v == parent) continue; |
| |
| get_matching(v, u, false, matching_edges); |
| } |
| } else { |
| |
| if (memo[u].val1 > memo[u].val0) { |
| |
| int v_match = memo[u].child_for_1; |
| for (auto& edge : adj[u]) { |
| if (edge.first == v_match) { |
| matching_edges.push_back(edge.second); |
| break; |
| } |
| } |
| |
| for (auto& edge : adj[u]) { |
| int v = edge.first; |
| if (v == parent) continue; |
| if (v == v_match) { |
| |
| get_matching(v, u, true, matching_edges); |
| } else { |
| |
| get_matching(v, u, false, matching_edges); |
| } |
| } |
| } else { |
| |
| for (auto& edge : adj[u]) { |
| int v = edge.first; |
| if (v == parent) continue; |
| get_matching(v, u, false, matching_edges); |
| } |
| } |
| } |
| } |
|
|
| void solve() { |
| cin >> n; |
| p.resize(n + 1); |
| for (int i = 1; i <= n; ++i) cin >> p[i]; |
| |
| adj.assign(n + 1, vector<pair<int, int>>()); |
| edge_list.clear(); |
| edge_list.resize(n); |
| for (int i = 1; i < n; ++i) { |
| int u, v; |
| cin >> u >> v; |
| adj[u].push_back({v, i}); |
| adj[v].push_back({u, i}); |
| edge_list[i] = {u, v, i}; |
| } |
| |
| |
| dists.assign(n + 1, vector<int>(n + 1)); |
| for (int i = 1; i <= n; ++i) bfs(i, dists[i]); |
| |
| vector<vector<int>> operations; |
| |
| while (true) { |
| |
| bool sorted = true; |
| for (int i = 1; i <= n; ++i) { |
| if (p[i] != i) { |
| sorted = false; |
| break; |
| } |
| } |
| if (sorted) break; |
| |
| weights.assign(n, 0); |
| |
| |
| for (int i = 1; i < n; ++i) { |
| int u = edge_list[i].u; |
| int v = edge_list[i].v; |
| int pu = p[u]; |
| int pv = p[v]; |
| |
| int d_old = dists[u][pu] + dists[v][pv]; |
| int d_new = dists[v][pu] + dists[u][pv]; |
| int gain = d_old - d_new; |
| |
| if (gain == 2) { |
| weights[i] = 100; |
| } else if (gain == 0) { |
| |
| |
| bool useful = false; |
| bool disrupts_target = false; |
| |
| |
| if (dists[v][pu] < dists[u][pu]) { |
| useful = true; |
| if (pv == v) disrupts_target = true; |
| } |
| |
| if (dists[u][pv] < dists[v][pv]) { |
| useful = true; |
| if (pu == u) disrupts_target = true; |
| } |
| |
| if (useful) { |
| if (disrupts_target) weights[i] = 5; |
| else weights[i] = 1; |
| } else { |
| weights[i] = 0; |
| } |
| } else { |
| weights[i] = 0; |
| } |
| } |
| |
| |
| memo.assign(n + 1, {0, 0, 0}); |
| dfs_dp(1, 0); |
| |
| vector<int> matching; |
| get_matching(1, 0, false, matching); |
| |
| if (matching.empty()) break; |
| |
| operations.push_back(matching); |
| |
| for (int idx : matching) { |
| int u = edge_list[idx].u; |
| int v = edge_list[idx].v; |
| swap(p[u], p[v]); |
| } |
| } |
| |
| cout << operations.size() << "\n"; |
| for (auto& op : operations) { |
| cout << op.size(); |
| for (int idx : op) cout << " " << idx; |
| cout << "\n"; |
| } |
| } |
|
|
| int main() { |
| ios_base::sync_with_stdio(false); |
| cin.tie(NULL); |
| int t; |
| if (cin >> t) { |
| while (t--) { |
| solve(); |
| } |
| } |
| return 0; |
| } |