1. 程式人生 > >Gym-101741C Cover the Paths(LCA+貪心)

Gym-101741C Cover the Paths(LCA+貪心)

C. Cover the Paths

time limit per test

1 second

memory limit per test

256 mebibytes

input

standard input

output

standard output

You are given an undirected unweighted tree consisting of n vertices labeled by integers 1, 2, ..., n. A total of m simple paths are chosen in this tree. Each path is described as a pair of its endpoints (a

i, bi).

Let V be the set of all vertices of the tree. We say that subset S of V is good if for every i such that 1 ≤ i ≤ m, the simple path from ai to bicontains at least one vertex from S. We say that subset T be the best subset if T is a good subset and there is no good subset X such that |X| < |T

|.

You have to find the best subset of V.

Input

The first line contains an integer n, the number of vertices in the tree (1 ≤ n ≤ 105).

Each of the next n - 1 lines describes an edge of the tree. Edge i is denoted by two integers ui and vi, the labels of vertices it connects (1 ≤ ui, vi ≤ nui ≠ v

i). It is guaranteed that the given edges form a tree.

The next line contains an integer m, the number of paths (1 ≤ m ≤ 105).

Each of the next m lines describes a path in the tree. Path i is denoted by two integers ai and bi, the labels of the endpoints (1 ≤ ai, bi ≤ n). For some paths, it may be that ai = bi. It is not guaranteed that all paths are pairwise distinct.

Output

On the first line, print the size of the best subset of V. On the second line, print the labels of vertices belonging to the best subset of V in any order.

If there are several possible solutions, print any one of them.

Examples

input

Copy

4
1 2
2 3
2 4
2
1 2
4 2

output

Copy

1
2 

input

Copy

6
1 2
2 3
3 4
5 6
5 2
5
2 1
6 6
1 4
3 4
4 1

output

Copy

3
6 3 1 

題意:樹上有m條路徑,要求找出最小的點集,使得每一條路徑至少經過點集中的一個點

題解:找出每條路徑的LCA,根據LCA的深度(從大到小)排序,然後依次貪心地將LCA加入點集即可。

#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define x first
#define y second
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define per(i,a,b) for(int i=a-1;i>=(b);--i)
#define fuck(x) cout<<'['<<#x<<' '<<(x)<<']'<<endl
#define clr(a,b) memset(a,b,sizeof(a))
#define eps 1e-10
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef vector<int> VI;
typedef pair<int, int> PII;
typedef unsigned int ui;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
const int mod = 1e9 + 7;
const int MX = 1e5 + 5;
struct Tree {
    int n;
    vector <int> T;
    void init (int _n) {
        if (T.empty()) T.resize(MX);
        else for (int i = 0; i <= _n; i++) T[i] = 0;
        n = _n;
    }
    void add(int x, int v) {
        for (int i = x; i <= n; i += i & -i) T[i] += v;
    }
    int sum(int x) {
        if (x > n) x = n;
        int ret = 0;
        for (int i = x; i > 0; i -= i & -i) ret += T[i];
        return ret;
    }
} t;

struct Edge {
    int v, nxt;
} E[MX * 2];
int head[MX], tot;
void edge_add(int u, int v) {
    E[tot].v = v;
    E[tot].nxt = head[u];
    head[u] = tot++;
}
int pre[MX], tp[MX], sz[MX], son[MX], vis[MX], deep[MX], f[MX], rear;
void init (int n) {
    for (int i = 1; i <= n; i++) head[i] = -1;
    for (int i = 0; i <= n; i++) vis[i] = 0;
    tot = rear = 0;
}
void dfs (int u, int dep, int top) {
    if(sz[u]) {
        vis[u] = 1, tp[u] = top, f[u] = ++rear;
        if(son[u]) dfs(son[u], dep, top);
        else return;
        for(int i = head[u]; ~i; i = E[i].nxt) {
            int v = E[i].v;
            if(v == pre[u] || vis[v]) continue;
            dfs(v, dep, v);
        }
    } else {
        sz[u] = 1, deep[u] = dep;
        for (int i = head[u]; ~i; i = E[i].nxt) {
            int v = E[i].v;
            if (v == pre[u]) continue;
            pre[v] = u;
            dfs (v, dep + 1, top);
            sz[u] += sz[v];
            son[u] = sz[v] > sz[son[u]] ? v : son[u];
        }
    }
}
int LCA(int u, int v) {
    int f1 = tp[u], f2 = tp[v];
    while(f1 != f2) {
        if(deep[f1] < deep[f2]) {
            swap(f1, f2);
            swap(u, v);
        }
        u = pre[f1]; f1 = tp[u];
    }
    return deep[u] < deep[v] ? u : v;
}
void pre_solve (int n) {
    t.init (n);
    dfs(1, 0, 1);
    dfs(1, 0, 1);
}
void add(int u, int x) {
    t.add(f[u], x);
}
int query(int u, int v) {
    int f1 = tp[u], f2 = tp[v], ret = 0;
    while(f1 != f2) {
        if(deep[f1] < deep[f2]) {
            swap(f1, f2);
            swap(u, v);
        }
        ret += t.sum(f[u]) - t.sum(f[f1] - 1);
        u = pre[f1]; f1 = tp[u];
    }
    if(deep[u] < deep[v]) swap(u, v);
    ret += t.sum(f[u]) - t.sum(f[v] - 1);
    return ret;
}
struct node {
    int u, v, lca;
    bool operator<(const node& _A) const {
        return deep[lca] > deep[_A.lca];
    }
} p[MX];

int main() {
#ifdef local
    freopen("in.txt", "r", stdin);
#endif // local
    int n; cin >> n;
    init(n);
    rep(i, 1, n) {
        int u, v; scanf("%d%d", &u, &v);
        edge_add(u, v);
        edge_add(v, u);
    }
    pre_solve(n);
    int m; cin >> m;
    rep(i, 1, m + 1) {
        scanf("%d%d", &p[i].u, &p[i].v);
        p[i].lca = LCA(p[i].u, p[i].v);
    }
    sort(p + 1, p + m + 1);
    vector<int>ver;
    rep(i, 1, m + 1) {
        if(query(p[i].u, p[i].v)) continue;
        ver.pb(p[i].lca);
        add(p[i].lca, 1);
    }
    printf("%d\n", ver.size());
    rep(i, 0, ver.size()) printf("%d%c", ver[i], i == ver.size() - 1 ? '\n' : ' ');

    return 0;
}