codeforces gym-101741 Cover the Paths LCA, ask offline

topic

topic link

meaning of the title

Given a tree.
Given a bunch of paths, find at least a set of least points such that all paths pass through at least one point in the set.

answer

Consider the two endpoints of a path. The last point that can be passed from bottom to top is the LCA of these two points.
Therefore, we do the whole tree dfs, and judge whether the current node is the LCA of a certain path when backtracking. If so, then this point must be fetched, otherwise there will be at least one path that is not covered by the set points.
After taking this point, you need to cancel all the paths that this point passes through.

This question does not need to actually find the LCA. If a path query exists in two subtrees at the same time, then the current node is the LCA of the two endpoints of the path.
Therefore, it is only necessary to maintain a set of query labels for each node. In this way, when the same label is encountered for the first time in two sets to be merged, then this node is LCA.
Merge the set of subtrees and parent nodes each time backtracking (requires heuristic merge).

code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <unordered_set>
using namespace std;
const int maxn = 1e5+7;
int n,m;
vector<int> G[maxn];
unordered_set<int> st[maxn];
int ok[maxn];
void dfs(int u,int p){
    for(auto v : G[u]){
        if(v == p) continue;
        dfs(v,u);
        if(ok[u]) continue;
        if(st[u].size() < st[v].size()){
            swap(st[u],st[v]);
        }
        for(auto i : st[v]){
            if(st[u].find(i) != st[u].end()){
                ok[u] = 1;
                break;
            }
            st[u].insert(i);
        }
    }
    //如果该节点被取的,那么清空其询问标号集合,以表示把这个点经过的所有路径都标记掉。
    if(ok[u]) st[u].clear();

}
int main(){
    scanf("%d",&n);
    for(int i = 0;i < n-1;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    scanf("%d",&m);
    for(int i = 0;i < m;++i){
        int u,v;
        scanf("%d %d",&u,&v);
        if(u == v) ok[u] = 1;
        st[u].insert(i);
        st[v].insert(i);
    }
    dfs(1,0);
    vector<int> ans;
    for(int i = 1;i <= n;++i){
        if(ok[i]) ans.push_back(i);
    }
    printf("%d\n",ans.size());
    for(auto i : ans)
        printf("%d ",i);
    return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325762304&siteId=291194637
lca