点我看题
18.11.14 update:
PS 四个月之后再来看这道题,发现不会写了,感觉很真实
题意 给出一颗树,然后给出m条简单路径,定义一个集合S为好集合 当且仅当对于每一条简单路径 ,都至少有一个点包含在S内。
现在要你求出大小最小的S集合 。
首先就应该往LCA的方向上去想。 将树变成一颗有向树,从最深层的LCA开始考虑。
这里要判断一条路径上是否有点已经被选取,可以用树链剖分来写。
#include<iostream>
#include<cstdio>
#include <algorithm>
#include <string.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const int MAX=1e5+10;
int sum[MAX<<2];
void push_up(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int p,int l,int r,int rt){
if(l==r){
sum[rt]++;
return;
}
int m=(l+r)>>1;
if(m>=p){
update(p,lson);
}else{
update(p,rson);
}
push_up(rt);
}
int query(int L,int R,int l,int r,int rt){
if(l>=L && r<=R){
return sum[rt];
}
int ans=0;
int m=(l+r)>>1;
if(m>=L){
ans+=query(L,R,lson);
}
if(m<R){
ans+=query(L,R,rson);
}
return ans;
}
class Edge{
public:
int u,v,next;
};
int tot;
int head[MAX];
Edge edge[MAX<<1];
void add(int u,int v){
edge[tot].u=u;
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot;
tot++;
}
int a[MAX<<2];
int fa[MAX],top[MAX],siz[MAX],son[MAX],dep[MAX],id[MAX],rear;
void dfs1(int u,int f,int d){
fa[u]=f,dep[u]=d;
son[u]=0;
siz[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==f){
continue;
}
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v]){
son[u]=v;
}
}
}
void dfs2(int u,int tp){
top[u] = tp;
id[u]= ++rear;
if(son[u]) dfs2(son[u],tp);
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(v==fa[u]|| v==son[u]) continue;
dfs2(v,v);
}
}
void presolve(){
rear = 0;
dfs1(1,0,1);
dfs2(1,1);
}
void HDL_update(int x){
update(id[x],1,rear,1);
}
int HDL_query(int u,int v){
int tp1= top[u];
int tp2 = top[v];
int sum= 0;
while(tp1!=tp2){
if(dep[tp1]<dep[tp2]){
swap(u,v);
swap(tp1,tp2);
}
sum+=query(id[tp1],id[u],1,rear,1);
u=fa[tp1];
tp1=top[u];
}
if(dep[u]>dep[v]) swap(u,v);
sum+=query(id[u],id[v],1,rear,1);
return sum;
}
int lca(int u,int v){
int tp1=top[u],tp2=top[v];
while(tp1!=tp2){
if(dep[tp1]<dep[tp2]){
swap(u,v);
swap(tp1,tp2);
}
u=fa[tp1];
tp1=top[u];
}
return dep[u]>dep[v]? v:u;
}
class Node{
public:
int lca,a,b;
bool operator < (const Node &b)const{
return dep[lca]>dep[b.lca];
}
};
int main(){
memset(head,-1,sizeof head);
int n;
scanf("%d", &n);
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
add(u,v);
add(v,u);
}
presolve();
vector<Node> V;
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++){
Node cnt;
scanf("%d %d",&cnt.a,&cnt.b);
cnt.lca=lca(cnt.a,cnt.b);
V.push_back(cnt);
}
vector<int> ans;
sort(V.begin(),V.end());
for(int i=0;i<V.size();i++){
Node cnt = V[i];
if(HDL_query(cnt.a,cnt.b)>0) continue;
ans.push_back(cnt.lca);
HDL_update(cnt.lca);
}
cout<<ans.size()<<endl;
for(int i=0;i<ans.size();i++){
cout<<ans[i]<<" ";
}
return 0;
}