用线段树优化写的
#include <cmath>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define R register
const int N = 2e4 + 5;
const int inf = 0x3f3f3f3f;
inline int read() {
int x = 0, f = 1; char a = getchar();
for(; a > '9' || a < '0'; a = getchar()) if(a == '-') f = -1;
for(; a >= '0' && a <= '9'; a = getchar()) x = x * 10 + a - '0';
return x * f;
}
int n, m, S, T;
int tot;
int gtedge[N];
namespace Flow {
struct edge {
int to, next, f;
}e[N * 400];
int head[N * 6], cnt = 1;
inline void add(int x, int y, int f) {
//cout << x << ' ' << y << endl;
e[++ cnt] = {y, head[x], f}; head[x] = cnt;
e[++ cnt] = {x, head[y], 0}; head[y] = cnt;
}
int dep[N * 6], cur[N * 6];
//queue<int> q;
inline bool bfs() {
memset(dep, 0x3f, sizeof(dep));
//memcpy(cur, head, sizeof(cur));
for(R int i = 1; i <= T; i ++) cur[i] = head[i];
dep[S] = 0;
//while(q.size()) q.pop();
queue<int> q;
q.push(S);
while(q.size()) {
int x = q.front(); q.pop();
for(R int i = head[x]; i; i = e[i].next) {
if(e[i].f == 0) continue;
int y = e[i].to;
if(dep[y] != inf) continue;
dep[y] = dep[x] + 1;
// if(y == T) return 1;
q.push(y);
}
}
return dep[T] != inf;
//return 0;
}
inline int dfs(int x, int T, int lim) {
if(x == T || lim == 0) return lim;
int tmp = 0, flow = 0;
for(R int &i = cur[x]; i; i = e[i].next) {
int y = e[i].to;
if(dep[y] == dep[x] + 1 && (tmp = (dfs(y, T, min(e[i].f, lim))))) {
e[i].f -= tmp; e[i ^ 1].f += tmp;
flow += tmp; lim -= tmp;
if(lim == 0) break;
}
}
if(lim == 0) dep[x] = inf;
return flow;
}
inline int Dinic() {
int ans = 0;
while(bfs()) ans += dfs(S, T, inf);
return ans;
}
}
namespace Seg {
int t[N * 6], ls[N * 6], rs[N * 6];
inline void build(int &x, int l, int r) {
x = ++ tot;
if(l == r) {
Flow :: add(x, l, 1);
gtedge[l] = x;
return ;
}
int mid = (l + r) >> 1;
build(ls[x], l, mid);
build(rs[x], mid + 1, r);
Flow :: add(x, ls[x], inf);
Flow :: add(x, rs[x], inf);
}
inline void link(int x, int l, int r, int Le, int Ri, int nd) {
if(Le <= l && r <= Ri) { Flow :: add(nd, x, inf); return ;}
int mid = (l + r) >> 1;
if(Le <= mid) link(ls[x], l, mid, Le, Ri, nd);
if(Ri > mid) link(rs[x], mid + 1, r, Le, Ri, nd);
}
}
namespace Tree {
struct edge {
int to, next;
}e[N << 1];
int head[N], cnt = 1;
inline void add(int x, int y) {
e[++ cnt] = {y, head[x]}; head[x] = cnt;
e[++ cnt] = {x, head[y]}; head[y] = cnt;
}
int loc[N];
int dep[N], fa[N], top[N], dfn[N], num, sz[N], son[N];
inline void dfs1(int x, int fx) {
dep[x] = dep[fx] + 1;
fa[x] = fx;
sz[x] = 1;
for(R int i = head[x]; i; i = e[i].next) {
int y = e[i].to;
if(y == fx) continue;
loc[y] = i / 2;
dfs1(y, x);
if(sz[y] > sz[son[x]]) son[x] = y;
}
}
inline void dfs2(int x, int topx) {
dfn[x] = ++ num;
top[x] = topx;
if(son[x]) dfs2(son[x], topx);
for(R int i = head[x]; i; i = e[i].next) {
int y = e[i].to;
if(y == fa[x] || y == son[x]) continue;
dfs2(y, y);
}
}
inline void modify(int x, int y, int nd) {
//cout << x << ' ' << y << endl;
while(top[x] != top[y]) {
if(dep[x] < dep[y]) swap(x, y);
Seg :: link(Seg :: t[1], 1, n, dfn[top[x]], dfn[x], nd);
x = fa[top[x]];// cout << "31";
}
if(dep[x] > dep[y]) swap(x, y);
if(x != y) Seg :: link(Seg :: t[1], 1, n, dfn[x] + 1, dfn[y], nd);
}
inline void Init() {
dfs1(1, 0);
dfs2(1, 1);
Seg :: build(Seg :: t[1], 1, n);
//for(R int i = 1; i <= n; i ++) cout << top[i] << ' ' ;
}
}
int vis[N * 6];
inline void dfs(int x) {
vis[x] = 1;
for(R int i = Flow :: head[x]; i; i = Flow :: e[i].next) {
if(Flow :: e[i].f == 0) continue;
int y = Flow :: e[i].to;
if(vis[y] == 0) dfs(y);
}
}
int main() {
#ifdef IN
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
#endif
n = read(); m = read();
tot = n;
for(R int i = 1; i < n; i ++) {
int x = read(), y = read();
Tree :: add(x, y);
}
Tree :: Init();
S = tot + m + 1; T = tot + m + 2;
for(R int i = 1; i <= m; i ++) {
int x = read(), y = read();
Tree :: modify(x, y, tot + i);
Flow :: add(S, i + tot, 1);
}
//Tree :: modify(2, 3, tot + 5);
for(R int i = 2; i <= n; i ++) Flow :: add(i, T, 1);
printf("%d\n", Flow :: Dinic());
dfs(S);
vector <int> peo, gur;
for(R int i = 1; i <= m; i ++)
if(vis[i + tot] == 0) peo.push_back(i);
for(R int i = 2; i <= n; i ++)
if(vis[gtedge[Tree :: dfn[i]]]) gur.push_back(Tree :: loc[i]);
printf("%d ", (int)peo.size());
for(R int i = 0; i < peo.size(); i ++)
printf("%d ", peo[i]);
putchar('\n');
printf("%d ", (int)gur.size());
for(R int i = 0; i < gur.size(); i ++)
printf("%d ", gur[i]);
putchar('\n');
return 0;
}