题目地址:https://oj.neu.edu.cn/problem/1204
题目大意:
其实就是树上的线段覆盖,
给出一棵n个结点的树,然后给出树上的一些路径进行覆盖,然后要求选取最少的点,能够把这些线段都占有
(或者说:一开始树上每个结点权值都为0,选取最少的点,把它们的权重变成1,使得询问的每一条路径上有含有权值为1的结点)
题解:
类似线段覆盖(线段覆盖是按照右端点贪心)
这个题就是按照每个路径的lca的深度贪心
也就是说把询问按照lca的深度从大到小排序
然后依次枚举询问
如果当前询问的路径没有权值为1的结点,就把lca赋值成1,答案加1
如果有就跳过
最后输出就可以了
整个过程用树链剖分就可以维护
(第一次wa是没有多组输入输出,第二次wa是把return 0 放在多组数据里了,第三次wa是忘记删freopen。。。orz)
#include <algorithm> #include <cstring> #include <iostream> #include <cstdio> #include <vector> using namespace std; const int maxn = 1e5 + 100; const int maxm = 5e5 + 100; int tree[maxn*4], deep[maxn], p[maxn], sz[maxn], son[maxn], top[maxn], F[maxn]; int tot = 0; vector<int> G[maxn]; struct Que{ int x, y, lca; bool operator <(const Que& B) const{ return deep[lca] < deep[B.lca]; } }; vector<Que> Q; void Insert(int o, int l, int r, int k, int v){ if(l == r) { tree[o] = v; return; } int mid = (l+r)>>1; if(k <= mid) Insert(o*2, l, mid, k, v); else Insert(o*2+1, mid+1, r, k, v); tree[o] = max(tree[o*2], tree[o*2+1]); } int Query(int o, int l, int r, int L, int R){ if(L <= l && r <= R) return tree[o]; int mid = (l+r)>>1, ans = 0; if(L <= mid) ans = max(ans, Query(o*2, l, mid, L, R)); if(R > mid) ans = max(ans, Query(o*2+1, mid+1, r, L, R)); return ans; } int dfs1(int x, int fa, int d){ deep[x] = d; p[x] = fa; sz[x] = 1; for(auto to : G[x]){ if(fa == to) continue; sz[x] += dfs1(to, x, d+1); if(sz[to] > sz[son[x]]) son[x] = to; } return sz[x]; } void dfs2(int x, int fa){ F[x] = ++tot; if(son[fa] == x) top[x] = top[fa]; else top[x] = x; if(son[x]) dfs2(son[x], x); for(auto to : G[x]){ if(to == fa || to == son[x]) continue; dfs2(to, x); } } int TQuery(int x, int y, int &lca){ int ans = 0; while(top[x] != top[y]){ if(deep[top[y]] > deep[top[x]]) swap(x, y); ans = max(ans, Query(1, 1, tot, F[top[x]], F[x])); x = p[top[x]]; } if(deep[x] > deep[y]) swap(x, y); ans = max(ans, Query(1, 1, tot, F[x], F[y])); lca = x; return ans; } int main() { int n, m, x, y; while(cin>>n){ tot = 0; for(int i = 0; i <= n; i++) G[i].clear(); memset(son, 0, sizeof(son)); memset(tree, 0, sizeof(tree)); for(int i = 1; i <= n; i++){ scanf("%d %d", &x, &y); G[x].push_back(y); G[y].push_back(x); } dfs1(0, 0, 1); dfs2(0, 0); cin>>m; Q.resize(m); for(int i = 0; i < m; i++){ scanf("%d %d", &Q[i].x, &Q[i].y); TQuery(Q[i].x, Q[i].y, Q[i].lca); } sort(Q.begin(), Q.end()); reverse(Q.begin(), Q.end()); int ans = 0; for(auto a : Q){ int k = TQuery(a.x, a.y, a.lca); if(k) continue; else Insert(1, 1, tot, F[a.lca], 1), ans++; } cout<<ans<<endl; } return 0; }