题意:这道题和我上一篇发的题很像,题意是这样,给你一棵树,然后
给出m条路,让你求出一个最小点集,使得这个点集包含每一条路中最少一个点。
思路:树链剖分,然后求出m对路的lca,按照他们的lca深度从深到浅排序,
然后从深到浅开始dfs,每次dfs求出这一对点各自的链首,找出较深的那一个,
询问那一点到其链首中有没有点已经被选过,然后把那一点更新为那一点的链首的父亲的
链首。
题目链接
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
int n, m, u[N], v[N];
vector<int> G[N];
int lc[N], ans;
int fa[N], dep[N], idx[N], out[N], ridx[N];
struct Edge
{
int u, v, lca;
bool operator < (const Edge &e) const
{
return dep[lca] > dep[e.lca];
}
};
Edge edges[N];
struct BIT
{
int c[N];
void init()
{
memset(c, 0, sizeof c);
}
void add(int x, int d)
{
for (x++; x < N; x += x & -x)
c[x] += d;
}
int query(int x)
{
int ret = 0;
for (x++; x; x -= x & -x)
ret += c[x];
return ret;
}
} bit;
namespace hld
{
int sz[N], son[N], top[N], clk;
void init()
{
clk = 0;
}
void predfs(int u, int d)
{
dep[u] = d;
sz[u] = 1;
int& maxs = son[u] = -1;
for (int& v: G[u])
{
if (v == fa[u]) continue;
fa[v] = u;
predfs(v, d + 1);
sz[u] += sz[v];
if (maxs == -1 || sz[v] > sz[maxs]) maxs = v;
}
}
void dfs(int u, int tp)
{
top[u] = tp;
idx[u] = ++clk;
ridx[clk] = u;
if (son[u] != -1) dfs(son[u], tp);
for (int& v: G[u])
if (v != fa[u] && v != son[u]) dfs(v, v);
out[u] = clk;
}
template<typename T>
int go(int u, int v, T&& f)
{
// cout<<endl<<endl<<"******"<<endl;
int uu = top[u], vv = top[v];
// cout<<uu<<" "<<vv<<" "<<u<<" "<<v<<endl;
while (uu != vv)
{
if (dep[uu] < dep[vv])
{
swap(uu, vv);
swap(u, v);
}
// cout<<uu<<" "<<u<<" "<<idx[uu]<<" "<<idx[u]<<"dfs序"<<endl;
f(idx[uu], idx[u]);
u = fa[uu];
uu = top[u];
// cout<<uu<<" "<<vv<<" "<<u<<" "<<v<<endl;
}
if (dep[u] < dep[v]) swap(u, v);
// choose one
f(idx[v], idx[u]);
// if (u != v) f(idx[v] + 1, idx[u]);
// cout<<endl<<endl<<"******"<<endl;
return v;
}
int go(int u, int v)
{
return go(u, v, [](int, int) {});
}
void add(int u)
{
bit.add(idx[u], 1);
}
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n - 1; ++i)
{
int a, b;
scanf("%d%d", &a, &b);
G[a].push_back(b);
G[b].push_back(a);
}
scanf("%d", &m);
for (int i = 0; i < m; ++i)
scanf("%d%d", &u[i], &v[i]);
hld::predfs(1, 1);
hld::dfs(1, 1);
for (int i = 0; i < m; ++i)
lc[i] = hld::go(u[i], v[i]);
// for (int i = 0; i < m; ++i)
// printf("%d %d %d\n", u[i], v[i], lc[i]);
// printf("结束了\n");
for (int i = 0; i < m; ++i)
edges[i] = {u[i], v[i], lc[i]};
sort(edges, edges + m);
vector<int> ans_list;
for (int i = 0; i < m; ++i)
{
int x = 0;
Edge &e = edges[i];
// printf("%d %d %d\n", e.u, e.v, e.lca);
hld::go(e.u, e.v, [&](int a, int b)
{
x += bit.query(b) - bit.query(a - 1);
});
cout << x << endl;
if (x) continue;
hld::add(e.lca);
ans++;
ans_list.push_back(e.lca);
}
//printf("答案:");
cout << ans << endl;
// printf("答案结束\n");
for (int i = 0; i < ans; ++i)
printf("%d%c", ans_list[i], i + 1 == ans ? '\n' : ' ');
}