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 (ai, 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 ≠ vi). 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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值