題目鏈接:Security Cameras
裸的支配樹,不知道爲什麼沒人寫。
首先我們對於B點,直接往上跳父親即可找到所有支配他的點。
但是我們要知道,跳父親的同時,父親是最近支配點,父親的父親的第二近的支配點。
所以最後reverse即可。
AC代碼:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e5+10,M=2e6;
int n,m,s,A,B;
struct Dominate_tree{
int cnt,tot,res,f[N],fa[N];
int head[N<<1],pre[N<<1],to[M<<1],nex[M<<1],lat[M],cdy[N<<1];
int bel[M],val[M],sdom[M],idom[M];
int dfn[M],id[M];
inline void add(int *head,int a,int b){
to[++tot]=b; nex[tot]=head[a]; head[a]=tot;
}
void dfs(int x){
dfn[x]=++cnt; id[cnt]=x;
for(int i=head[x];i;i=nex[i]){
if(dfn[to[i]]) continue;
dfs(to[i]); fa[to[i]]=x;
}
}
int find(int x){
if(x==bel[x]) return x;
int rt=find(bel[x]);
if(dfn[sdom[val[bel[x]]]]<dfn[sdom[val[x]]]) val[x]=val[bel[x]];
return bel[x]=rt;
}
void Tarjan(){
for(int i=cnt;i>=2;i--){
int x=id[i];
for(int j=pre[x];j;j=nex[j]){
if(!dfn[to[j]]) continue;
find(to[j]);
if(dfn[sdom[val[to[j]]]]<dfn[sdom[x]]) sdom[x]=sdom[val[to[j]]];
}
add(lat,sdom[x],x); bel[x]=fa[x]; x=fa[x];
for(int j=lat[x];j;j=nex[j]){
find(to[j]);
if(sdom[val[to[j]]]==x) idom[to[j]]=x;
else idom[to[j]]=val[to[j]];
}
lat[x]=0;
}
for(int i=2,x;i<=cnt;i++){
x=id[i];
if(idom[x]!=sdom[x]) idom[x]=idom[idom[x]];
}
}
void work(){
for(int i=1;i<=n;i++) sdom[i]=bel[i]=val[i]=i;
dfs(s); Tarjan(); tot=0;
for(int i=1;i<=n;i++) if(idom[i]) add(cdy,idom[i],i);
}
void dfs(int x,int fa){
f[x]=fa;
for(int i=cdy[x];i;i=nex[i]) dfs(to[i],x);
}
void init(){
cnt=tot=0;
for(int i=1;i<=n;i++){
cdy[i]=head[i]=lat[i]=pre[i]=0;
idom[i]=sdom[i]=dfn[i]=id[i]=f[i]=fa[i]=0;
}
}
void solve(){
cin>>n>>m; init();
cin>>A>>B; s=A;
for(int i=1,a,b;i<=m;i++)
scanf("%d %d",&a,&b),add(head,a,b),add(pre,b,a);
work(); dfs(s,s);
vector<int> res;
while(B!=A) res.push_back(B),B=f[B];
res.push_back(A);
reverse(res.begin(),res.end());
printf("%d\n",res.size());
for(int i:res) printf("%d ",i);puts("");
}
}t;
signed main(){
int T; cin>>T; while(T--) t.solve();
return 0;
}