Tarjan 总结
- 1.Tarjan求强连通分量
1.1.POJ-1236 Network of Schools.
1.2. POJ-1904 King’s Quest.
1.3 Codeforces-711D Directed Roads.
1.4 Codeforces-427C Checkposts.
1.5 Codevs-1866 HAOI2010软件安装. - 2. Tarjan求割点.
2.1 UOJ-67 新年的毒瘤.
2.2 HNOI2012 矿场搭建.
2.3 POI2008 BLO-Blockade. - 3. Tarjan求桥(割边).
3.1 Vijos-1769 网络的关键边.
写在前面的话
终于弄完了…QAQ
Tarjan求强连通分量
设 DFN[u] 为访问u节点的时间截, LOW[u] 为u节点能通过边访问到的最小的DFN[]的值,对于在同一个强连通分量的点,其根节点的 LOW[] 为这些点中最小的,并且满足 LOW[u]==DFN[u] ,那么可以使用栈来记录在访问 u 节点后,访问的节点,并且这些节点在同一个强连通分量中,再将它们标记,出栈即可;
void Tarjan(int u)
{
vis[stack[++index]=u]=1,DFN[u]=LOW[u]=++dfs_num;
for(int i=head[u];i;i=edge[i].next)
if(!DFN[edge[i].to])
Tarjan(edge[i].to),
LOW[u]=min(LOW[u],LOW[edge[i].to]);
else if(vis[edge[i].to]) LOW[u]=min(LOW[u],DFN[edge[i].to]);
if(LOW[u]==DFN[u])
{
vis[u]=0,dye[u]=++CNT;
while(u!=stack[index])
{
vis[stack[index]]=0;
dye[stack[index--]]=CNT;
}
index--;
}
}
Network of Schools
POJ-1236
题目大意:
各节点之间存在单向边,某个节点得到软件后可以向相连的节点传输,
Q1:求最少发送多少软件,可以使全部节点得到软件,
Q2:求至少需要添加多少条边,使任意点之间能够联通
TJ
首先强联通分量乱搞,对于Q1,只需要找缩完点后入度为0的联通块的个数,对于Q2,要使所有的联通块均有出入度,只需要加上
King’s Quest
POJ-1904
题目大意
国王有
n
个王子,现在有
TJ
对于每个王子的心仪女孩,都连一条从王子到女孩的红线有向边,再从巫师的名单中添加从钦定女孩至王子的有向边,跑强连通分量,最后对于某王子,在同一强连通分量里的女孩都是可以选的
Directed Roads
题目大意
给定一个图,
TJ
对于在同一个强连通分量中的点,将边反向的方案数为
Checkposts
题目大意
给定一个有向图,每个节点有一个权值,在每个强连通分量中选一个点,求最小权值和在权值和最小的情况下可以选择的方案数
TJ
Tarjan乱搞,弄完之后在每个强联通分量中局部枚举,方案数乘法原理乘一下就好了
HAOI2010软件安装
题目大意
对于每个软件都有一个占用空间
wi
,还要一个价值
vi
,同时某些软件之间存在依赖关系,求在给定的
wmax
下得到的最大的
vmax
TJ
建立从被依赖的软件到需要依赖的软件的一条有向边,跑一遍Tarjan缩点,然后跑树上的背包DP,(泛化背包)
Tarjan求割点
割点,即删去该点和所有与该点相连的边后,图变成不连通的多个联通块
对于某个点
u
,如果该点成为割点,需满足在该点所连的某点
void tarjan(int u,int fa)
{
DFN[u]=LOW[u]=++dfs_num,vis[u]=1;
for(int i=head[u];i;i=E[i].next)
{
int to=E[i].to;
if(to==fa) continue;
if(!DFN[to])
{
tarjan(to,u);
LOW[u]=min(LOW[u],LOW[to]);
if(u==ant) son++; //情况2的特判
if(LOW[to]>=DFN[u] && u!=ant) cnt[u]=1;
}
else if(vis[to]) LOW[u]=min(LOW[u],DFN[to]);
}
}
新年的毒瘤
题目大意
给定一个有
n
个节点的
毒瘤点的定义:删去该点
u
之后,图成为树
TJ
考虑这样的节点
HNOI2012 矿场搭建
题目大意
给定一个无向图,求某个点爆炸后,其他点的工人仍有一条到达出口的道路,求需设置的最少出口和方案数
TJ
考虑割点,如果多个割点同时存在一个联通块中,那么就不必设置出口,因为某个割点爆炸后,还可以从其他割点出去,如果一个联通块中只有一个割点,那么就必须设置一个出口,并且不能设置在割点上,如果该联通块中没有割点,那么就要设置两个,防止其中一个爆炸
POI2008 BLO-Blockade
题目大意
很清楚…注意该点也包含在答案内
TJ
对于割点,封锁后分成的联通块之间的点不能相互到达,记忆化搜索,统计答案
Tarjan求割边(桥)
只需要将判断条件改为 LOW[v]>DFN[u] ,即可,因为对于某点如果无法到达父亲节点以上的节点,那么该点的边为桥
网络的关键边
题目大意
在给定的无向图中,某些点提供A或B服务,现要求求出所有的关键边
关键边的定义为:删去某条边
E
后,存在某个节点无法接受A或B服务
TJ
分析得到,关键边一定存在于桥上,并且要满足经过传递之后该边所连的点中的A,或B的值为0或
POJ-1236 Network of Schools
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=100+10;
int LOW[MAXN],DFN[MAXN],n,m,t,dfs_num,ans2;
int dye[MAXN],CNT,stack[MAXN],index1,size[MAXN];
int head[MAXN],num,ans1,in[MAXN],out[MAXN];
bool vis[MAXN];
struct Edge{
int from,to,next;
}edge[MAXN<<5];
void Add(int from,int to)
{
edge[++num].from=from;
edge[num].to=to;
edge[num].next=head[from];
head[from]=num;
}
void Tarjan(int u)
{
vis[stack[++index1]=u]=1;
DFN[u]=LOW[u]=++dfs_num;
for(int i=head[u];i;i=edge[i].next)
if(!DFN[edge[i].to])
{
Tarjan(edge[i].to);
LOW[u]=min(LOW[u],LOW[edge[i].to]);
}
else if(vis[edge[i].to]) LOW[u]=min(LOW[u],DFN[edge[i].to]);
if(DFN[u]==LOW[u])
{
vis[u]=0;
size[dye[u]=++CNT]++;
while(u!=stack[index1])
{
dye[stack[index1]]=CNT;
vis[stack[index1--]]=0;
size[CNT]++;
}
index1--;
}
}
void init()
{
memset(size,0,sizeof size);
memset(vis,0,sizeof vis);
memset(DFN,0,sizeof DFN);
memset(dye,0,sizeof dye);
memset(LOW,0,sizeof LOW);
num=0,CNT=0,index1=0,dfs_num=0,ans1=0,ans2=0;
memset(edge,0,sizeof edge);
memset(head,0,sizeof head);
memset(in,0,sizeof in);
memset(out,0,sizeof out);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
for(int i=1;i<=n;i++)
{
while(scanf("%d",&t))
{
if(t==0) break;
Add(i,t);
}
}
for(int i=1;i<=n;i++)
if(!dye[i]) Tarjan(i);
for(int i=1;i<=num;i++)
{
if(dye[edge[i].from]!=dye[edge[i].to])
{
in[dye[edge[i].to]]++;
out[dye[edge[i].from]]++;
}
}
for(int i=1;i<=CNT;i++)
{
if(in[i]==0) ans1++;
if(out[i]==0) ans2++;
}
if(CNT==1) printf("1\n0\n");
else printf("%d\n%d\n",ans1,max(ans1,ans2));
}
return 0;
}
POJ-1904 King’s Quest
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN=10000+10;
int LOW[MAXN],DFN[MAXN],dfs_num,dye[MAXN],in[MAXN],CNT,n1,tmp[MAXN];
int stack[MAXN],index1,n,m,x,y,head[MAXN],num,size[MAXN],k,a[MAXN],cnt[MAXN];
bool vis[MAXN];
struct Edge{
int from,to,next;
}E[MAXN<<5];
void Add(int from,int to)
{
E[++num].from=from;
E[num].to=to;
E[num].next=head[from];
head[from]=num;
}
void tarjan(int u)
{
vis[stack[++index1]=u]=1;
DFN[u]=LOW[u]=++dfs_num;
for(int i=head[u];i;i=E[i].next)
if(!DFN[E[i].to])
tarjan(E[i].to),LOW[u]=min(LOW[u],LOW[E[i].to]);
else if(vis[E[i].to]) LOW[u]=min(LOW[u],DFN[E[i].to]);
if(DFN[u]==LOW[u])
{
dye[u]=++CNT,vis[u]=0,size[CNT]++;
while(u!=stack[index1])
{
dye[stack[index1]]=CNT;
size[CNT]++;
vis[stack[index1--]]=0;
}
index1--;
}
}
void init()
{
memset(size,0,sizeof size);
memset(vis,0,sizeof vis);
memset(DFN,0,sizeof DFN);
memset(dye,0,sizeof dye);
memset(LOW,0,sizeof LOW);
num=CNT=index1=dfs_num=0;
memset(E,0,sizeof E);
memset(head,0,sizeof head);
}
bool cmp(int A,int B) {return A<B;}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
for(int i=1;i<=n;i++)
{
scanf("%d",&n1);
for(int j=1;j<=n1;j++)
{
scanf("%d",&x);
Add(i+n,x);
}
}
for(int i=1;i<=n;i++) {scanf("%d",&x);Add(x,i+n);}
for(int i=1;i<=n+n;i++)
if(!dye[i]) tarjan(i);
for(int i=n+1;i<=n+n;i++)
{
memset(tmp,0,sizeof tmp);
for(int j=head[i];j;j=E[j].next)
if(dye[E[j].to]==dye[i]) tmp[++tmp[0]]=E[j].to;
sort(tmp+1,tmp+tmp[0]+1,cmp);
printf("%d ",tmp[0]);
for(int j=1;j<=tmp[0];j++) printf("%d ",tmp[j]);
puts("");
}
}
return 0;
}
Codeforces-711D Directed Roads
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN=200000+10;
const int INF=0x7fffffff;
const int MOD=1000000007;
int LOW[MAXN],DFN[MAXN],dfs_num,dye[MAXN],in[MAXN],CNT,minn[MAXN];
int stack[MAXN],index1,n,m,x,y,head[MAXN],num,size[MAXN],k;
LL ans=1;
bool vis[MAXN];
struct Edge{
int from,to,next;
}E[MAXN<<2];
void Add(int from,int to)
{
E[++num].from=from;
E[num].to=to;
E[num].next=head[from];
head[from]=num;
}
void tarjan(int u)
{
vis[stack[++index1]=u]=1;
DFN[u]=LOW[u]=++dfs_num;
for(int i=head[u];i;i=E[i].next)
if(!DFN[E[i].to])
tarjan(E[i].to),LOW[u]=min(LOW[u],LOW[E[i].to]);
else if(vis[E[i].to]) LOW[u]=min(LOW[u],DFN[E[i].to]);
if(DFN[u]==LOW[u])
{
dye[u]=++CNT,vis[u]=0,size[CNT]++;
while(u!=stack[index1])
{
dye[stack[index1]]=CNT;
size[CNT]++;
vis[stack[index1--]]=0;
}
index1--;
}
}
void init()
{
memset(vis,0,sizeof vis);
memset(dye,0,sizeof dye);
memset(E,0,sizeof E);
memset(LOW,0,sizeof LOW);
memset(stack,0,sizeof stack);
memset(DFN,0,sizeof DFN);
memset(in,0,sizeof in);
memset(head,0,sizeof head);
for(int i=1;i<=MAXN;i++) minn[i]=INF;
num=dfs_num=ans=index1=CNT=0;
}
LL pow(LL a,LL b)
{
LL ans1=1,p=a;
while(b)
{
if(b & 1) ans1=(ans1*p)%MOD;
p=(p*p)%MOD;
b>>=1;
}
return ans1%MOD;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
init();
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
Add(i,x);
}
for(int i=1;i<=n;i++)
if(!dye[i]) tarjan(i);
ans=1;
for(int i=1;i<=CNT;i++)
if(size[i]>1) ans=(ans*(pow(2,size[i])%MOD-2))%MOD;
else if(size[i]==1) k++;
if(k!=0) ans=ans*pow(2,k)%MOD;
printf("%lld\n",ans);
}
}
Codeforces-427C Checkposts
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int MAXN=200000+10;
const int INF=0x7fffffff;
const int MOD=1000000007;
int LOW[MAXN],DFN[MAXN],dfs_num,dye[MAXN],in[MAXN],CNT,minn[MAXN];
int stack[MAXN],index1,n,m,x,y,head[MAXN],num,size[MAXN],k,a[MAXN],cnt[MAXN];
LL ans=1;
bool vis[MAXN];
struct Edge{
int from,to,next;
}E[MAXN<<2];
void Add(int from,int to)
{
E[++num].from=from;
E[num].to=to;
E[num].next=head[from];
head[from]=num;
}
void tarjan(int u)
{
vis[stack[++index1]=u]=1;
DFN[u]=LOW[u]=++dfs_num;
for(int i=head[u];i;i=E[i].next)
if(!DFN[E[i].to])
tarjan(E[i].to),LOW[u]=min(LOW[u],LOW[E[i].to]);
else if(vis[E[i].to]) LOW[u]=min(LOW[u],DFN[E[i].to]);
if(DFN[u]==LOW[u])
{
dye[u]=++CNT,vis[u]=0,size[CNT]++;
while(u!=stack[index1])
{
dye[stack[index1]]=CNT;
size[CNT]++;
vis[stack[index1--]]=0;
}
index1--;
}
}
LL pow(LL a,LL b)
{
LL ans1=1,p=a;
while(b)
{
if(b & 1) ans1=(ans1*p)%MOD;
p=(p*p)%MOD;
b>>=1;
}
return ans1%MOD;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
Add(x,y);
}
for(int i=1;i<=n;i++)
if(!dye[i]) tarjan(i);
LL ans=1,anss=0;
for(int i=1;i<=CNT;i++) minn[i]=INF;
for(int i=1;i<=n;i++)
if(minn[dye[i]]==a[i]) cnt[dye[i]]++;
else if(minn[dye[i]]>a[i]) minn[dye[i]]=a[i],cnt[dye[i]]=1;
for(int i=1;i<=CNT;i++)
anss+=minn[i],ans=(ans*cnt[i])%MOD;
printf("%lld %lld\n",anss,ans%MOD);
return 0;
}
Codevs-1866 HAOI2010软件安装
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
using namespace std;
const int MAXN=500+10;
int DFN[MAXN],LOW[MAXN],n,m,dfs_num,num,dye[MAXN],x,ans,num2,head1[MAXN],in[MAXN];
int stack[MAXN],index1,CNT,head[MAXN],w[MAXN],val[MAXN],f[MAXN][MAXN];
bool vis[MAXN];
struct Edge{
int from,to,next;
}E[MAXN<<1],E1[MAXN<<1];
struct Point{
int v,w,d;
}p[MAXN];
void Add(int from,int to)
{
E[++num].to=to;
E[num].from=from;
E[num].next=head[from];
head[from]=num;
}
void Add2(int from,int to)
{
in[to]++;
E1[++num2].to=to;
E1[num2].from=from;
E1[num2].next=head1[from];
head1[from]=num2;
}
void tarjan(int u)
{
vis[stack[++index1]=u]=1,DFN[u]=LOW[u]=++dfs_num;
for(int i=head[u];i;i=E[i].next)
if(!DFN[E[i].to])
tarjan(E[i].to),LOW[u]=min(LOW[u],LOW[E[i].to]);
else if(vis[E[i].to]) LOW[u]=min(LOW[u],DFN[E[i].to]);
if(LOW[u]==DFN[u])
{
vis[u]=0,p[++CNT].w=w[u],p[CNT].v=val[u],dye[u]=CNT;
while(u!=stack[index1])
{
vis[stack[index1]]=0,p[CNT].w+=w[stack[index1]];
p[CNT].v+=val[stack[index1]],dye[stack[index1--]]=CNT;
}
index1--;
}
}
void dfs(int pos)
{
for(int i=head1[pos];i;i=E1[i].next)
{
dfs(E1[i].to);
for(int j=m-p[pos].w;j>=0;j--)
for(int k=0;k<=j;k++)
f[pos][j]=max(f[pos][j],f[pos][k]+f[E1[i].to][j-k]);
}
for(int j=m;j>=0;j--)
if(j>=p[pos].w) f[pos][j]=f[pos][j-p[pos].w]+p[pos].v;
else f[pos][j]=0;
}
bool cmp(Point A,Point B) {return A.w<B.w;}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&w[i]);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]);
for(int i=1;i<=n;i++)
{scanf("%d",&x);if(x!=0) Add(x,i);}
for(int i=1;i<=n;i++)
if(!DFN[i]) tarjan(i);
for(int i=1;i<=num;i++)
if(dye[E[i].to]!=dye[E[i].from]) Add2(dye[E[i].from],dye[E[i].to]);
for(int i=1;i<=CNT;i++)
if(in[i]==0) Add2(CNT+1,i);
dfs(CNT+1);
printf("%d\n",f[CNT+1][m]);
return 0;
}
UOJ-67 新年的毒瘤
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN=500000+10;
int DFN[MAXN],LOW[MAXN],dfs_num,num,tmp[MAXN],n,m,x,y,in[MAXN];
int head[MAXN],son,ans[MAXN],ant;
bool vis[MAXN],cnt[MAXN];
struct Edge{
int from,to,next;
}E[MAXN<<1];
void Add(int from,int to)
{
E[++num].from=from;
E[num].to=to;
E[num].next=head[from];
head[from]=num;
}
void tarjan(int u,int fa)
{
DFN[u]=LOW[u]=++dfs_num,vis[u]=1;
for(int i=head[u];i;i=E[i].next)
{
int to=E[i].to;
if(to==fa) continue;
if(!DFN[to])
{
tarjan(to,u);
LOW[u]=min(LOW[u],LOW[to]);
if(u==ant) son++;
if(LOW[to]>=DFN[u] && u!=ant) cnt[u]=1;
}
else if(vis[to]) LOW[u]=min(LOW[u],DFN[to]);
}
}
bool cmp(int A,int B) {return A<B;}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
Add(x,y),Add(y,x);
}
for(int i=1;i<=n;i++)
if(!DFN[i])
{
son=0,ant=i;
tarjan(i,-1);
if(son>1) cnt[ant]=1;
}
for(int i=1;i<=num;i++)
in[E[i].to]++;
for(int i=1;i<=n;i++)
if(!cnt[i] && in[i]==m-n+2 )
ans[++ans[0]]=i;
sort(ans+1,ans+ans[0]+1,cmp);
printf("%d\n",ans[0]);
for(int i=1;i<=ans[0];i++)
printf("%d ",ans[i]);
return 0;
}
HNOI2012 矿场搭建
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int MAXN=4000+10;
int LOW[MAXN],DFN[MAXN],num,dfs_num,CNT,head[MAXN],n,x,y,ant,k,son,maxn,case1;
LL ans1,ans2;
bool vis[MAXN],cnt[MAXN];
struct Edge{
int from,to,next;
}E[MAXN<<1];
void Add(int from,int to)
{
E[++num].from=from;
E[num].to=to;
E[num].next=head[from];
head[from]=num;
}
void tarjan(int u,int fa)
{
LOW[u]=DFN[u]=++dfs_num,vis[u]=1;
for(int i=head[u];i;i=E[i].next)
{
int to=E[i].to;
if(to==fa) continue;
if(!DFN[to])
{
tarjan(to,u);
LOW[u]=min(LOW[u],LOW[to]);
if(u==ant) son++;
if(LOW[to]>=DFN[u] && u!=ant)
cnt[u]=1;
}
else if(vis[to]) LOW[u]=min(LOW[u],DFN[to]);
}
}
void dfs(int u)
{
DFN[u]=k;
if(cnt[u]) return ;
x++;
for(int i=head[u];i;i=E[i].next)
{
int to=E[i].to;
if(cnt[to] && DFN[to]!=k) CNT++,DFN[to]=k;
if(!DFN[to]) dfs(to);
}
}
void init()
{
memset(vis,0,sizeof vis);
memset(DFN,0,sizeof DFN);
memset(head,0,sizeof head);
memset(E,0,sizeof E);
memset(LOW,0,sizeof LOW);
memset(cnt,0,sizeof cnt);
num=CNT=ans1=dfs_num=maxn=k=0;
ans2=1;
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
init();
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x,&y);
Add(x,y),Add(y,x);
maxn=max( maxn, max(x,y) );
}
for(int i=1;i<=maxn;i++)
{
if(!DFN[i])
{
son=0;ant=i;
tarjan(i,-1);
if(son>=2) cnt[ant]=1;
}
}
memset(DFN,0,sizeof DFN);
for(int i=1;i<=maxn;i++)
{
if( !DFN[i] && !cnt[i] )
{
CNT=x=0,k++;
dfs(i);
if(!CNT) ans1+=2,ans2*=( x * (x-1) ) /2;
if(CNT==1) ans1++,ans2*=x;
}
}
printf("Case %d: %lld %lld\n",++case1,ans1,ans2);
}
return 0;
}
POI2008 BLO-Blockade
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=100000+10;
typedef long long LL;
int DFN[MAXN],LOW[MAXN],n,m,dfs_num,CNT,a,b;
int sum[MAXN],head[MAXN],num;
LL size[MAXN],ans[MAXN];
struct Edge{
int from,to,next;
}E[MAXN<<4];
void Add(int from,int to)
{
E[++num].from=from;
E[num].to=to;
E[num].next=head[from];
head[from]=num;
}
void tarjan(int u,int fa)
{
LL t=0;
DFN[u]=LOW[u]=++dfs_num;
size[u]=1;
for(int i=head[u];i;i=E[i].next)
{
if(E[i].to==fa) continue;
if(!DFN[E[i].to])
{
tarjan(E[i].to,u);
size[u]+=size[E[i].to];
LOW[u]=min(LOW[u],LOW[E[i].to]);
if(LOW[E[i].to]>=DFN[u])
{
ans[u]+=t*size[E[i].to];
t+=size[E[i].to];
}
}
else if(size[E[i].to]) LOW[u]=min(LOW[u],DFN[E[i].to]);
}
ans[u]+=t*(n-t-1);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
Add(a,b),Add(b,a);
}
tarjan(1,-1);
for(int i=1;i<=n;i++)
printf("%lld\n",ans[i]+(n-1)<<1);
return 0;
}
Vijos-1769 网络的关键边
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN=200000+10;
int LOW[MAXN],DFN[MAXN],head[MAXN],k,l,n,m,dfs_num,num,pre[MAXN],ans[MAXN],x,y;
int A[MAXN],B[MAXN],tmp[MAXN];
bool vis[MAXN],cnt[MAXN];
struct Edge{
int from,to,next,num;
}E[MAXN<<2];
void Add(int from,int to)
{
E[++num].from=from;
E[num].to=to;
E[num].num=num;
E[num].next=head[from];
head[from]=num;
}
void tarjan(int u,int fa)
{
vis[u]=1,LOW[u]=DFN[u]=++dfs_num;
for(int i=head[u];i;i=E[i].next)
{
int to=E[i].to;
if(to==fa) continue;
if(!DFN[to])
{
tarjan(to,u);
if(LOW[to]>DFN[u]) cnt[E[i].num]=1;
LOW[u]=min(LOW[u],LOW[to]);
}
else LOW[u]=min(LOW[u],DFN[to]);
}
}
void dfs(int u,int fa)
{
vis[u]=1,DFN[u]=DFN[fa]+1;
for(int i=head[u];i;i=E[i].next)
{
int to=E[i].to;
if(to==fa||vis[to]) continue;
dfs(to,u);
A[u]+=A[to];
B[u]+=B[to];
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&k,&l);
for(int i=1;i<=k;i++)
{
scanf("%d",&x);
A[x]++;
}
for(int i=1;i<=l;i++)
{
scanf("%d",&x);
B[x]++;
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
Add(x,y),Add(y,x);
}
for(int i=1;i<=n;i++)
if(!DFN[i]) tarjan(i,-1);
for(int i=1;i<=num;i++)
if(cnt[i]) tmp[++tmp[0]]=i;
memset(DFN,0,sizeof DFN);
memset(vis,0,sizeof vis);
dfs(1,-1);
for(int i=1;i<=tmp[0];i++)
{
int v=E[tmp[i]].to,u=E[tmp[i]].from;
if(DFN[v]<DFN[u]) swap(u,v);
if(A[v]==0||B[v]==0||A[v]==k||B[v]==l)
ans[++ans[0]]=tmp[i];
}
printf("%d\n",ans[0]);
for(int i=1;i<=ans[0];i++)
printf("%d\n",(ans[i]+1)/2);
return 0;
}