File size: 4,640 Bytes
1fd0050
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <iostream>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstring>
using namespace std;

const int MAXN = 1005;

int dist[MAXN][MAXN];
vector<int> adj[MAXN];

void bfs(int start, int n) {
    vector<int>& d = dist[start];
    for (int i = 1; i <= n; i++) d[i] = -1;
    queue<int> q;
    q.push(start);
    d[start] = 0;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        for (int v : adj[u]) {
            if (d[v] == -1) {
                d[v] = d[u] + 1;
                q.push(v);
            }
        }
    }
}

void solve() {
    int n;
    cin >> n;
    vector<int> p(n+1);
    for (int i = 1; i <= n; i++) cin >> p[i];
    
    vector<pair<int,int>> edges(n-1);
    for (int i = 1; i <= n; i++) adj[i].clear();
    for (int i = 0; i < n-1; i++) {
        int u, v;
        cin >> u >> v;
        edges[i] = {u, v};
        adj[u].push_back(v);
        adj[v].push_back(u);
    }
    
    // compute all-pairs distances
    for (int i = 1; i <= n; i++) bfs(i, n);
    
    // current token at each vertex
    vector<int> a = p;
    // phi[t] = vertex where token t is located
    vector<int> phi(n+1);
    for (int v = 1; v <= n; v++) phi[a[v]] = v;
    
    vector<vector<int>> operations;
    
    while (true) {
        // check if sorted
        bool sorted = true;
        for (int v = 1; v <= n; v++) if (a[v] != v) { sorted = false; break; }
        if (sorted) break;
        
        // find cycles in phi
        vector<int> cycle_id(n+1, -1);
        int cycle_cnt = 0;
        for (int i = 1; i <= n; i++) {
            if (cycle_id[i] == -1) {
                int j = i;
                do {
                    cycle_id[j] = cycle_cnt;
                    j = phi[j];
                } while (j != i);
                cycle_cnt++;
            }
        }
        
        // candidate edges
        struct Cand {
            int eid, gain, u, v;
            bool same_cycle;
        };
        vector<Cand> candidates;
        for (int eid = 0; eid < n-1; eid++) {
            int u = edges[eid].first, v = edges[eid].second;
            int i = a[u], j = a[v];
            int cur_dist = dist[u][i] + dist[v][j];
            int new_dist = dist[v][i] + dist[u][j];
            int gain = cur_dist - new_dist;
            bool same_cycle = (cycle_id[i] == cycle_id[j]);
            // consider edges that either have positive gain or are in same cycle
            if (gain > 0 || same_cycle) {
                candidates.push_back({eid, gain, u, v, same_cycle});
            }
        }
        
        // sort: positive gain first (higher gain first), then same_cycle edges
        sort(candidates.begin(), candidates.end(), [](const Cand& x, const Cand& y) {
            if (x.gain > 0 && y.gain > 0) return x.gain > y.gain;
            if (x.gain > 0) return true;
            if (y.gain > 0) return false;
            if (x.same_cycle && !y.same_cycle) return true;
            if (!x.same_cycle && y.same_cycle) return false;
            return x.gain > y.gain; // both zero gain and same_cycle status
        });
        
        vector<bool> used(n+1, false);
        vector<int> matching;
        for (auto& cand : candidates) {
            if (!used[cand.u] && !used[cand.v]) {
                used[cand.u] = used[cand.v] = true;
                matching.push_back(cand.eid);
            }
        }
        
        // if no edge selected, force an edge with at least one incorrect token
        if (matching.empty()) {
            for (int eid = 0; eid < n-1; eid++) {
                int u = edges[eid].first, v = edges[eid].second;
                if ((a[u] != u || a[v] != v) && !used[u] && !used[v]) {
                    matching.push_back(eid);
                    break;
                }
            }
        }
        
        // still empty (should not happen if not sorted), take first edge
        if (matching.empty() && n-1 > 0) {
            matching.push_back(0);
        }
        
        // apply the swaps
        for (int eid : matching) {
            int u = edges[eid].first, v = edges[eid].second;
            swap(a[u], a[v]);
        }
        
        // update phi
        for (int v = 1; v <= n; v++) phi[a[v]] = v;
        
        operations.push_back(matching);
    }
    
    // output
    cout << operations.size() << "\n";
    for (auto& op : operations) {
        cout << op.size();
        for (int eid : op) cout << " " << eid+1; // 1-based index
        cout << "\n";
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}