T集表示已经确定不在S集内的点。
对于一个点,如果不存在非T集的点挑战它,那么它一定在S集中。
如果存在一个挑战它的点在S集中,那么它一定在T集中。
用类似拓扑排序的方法,首先找出所有不被挑战的点,归入S,把这个点挑战的点y归入T集,然后y挑战的点的度数-1.
最后剩下一些点在环中,满足每个点都被别人挑战,也挑战别人,因为是二分图,所以保证是偶环,所以把<=n的未归入T的点归入S就行了。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 1e9
#define eps 1e-8
#define md
#define N 200010
using namespace std;
struct yts { int x,t,ne;} e[N];
int v[N],du[N],q[N],vis[N];
int num=0;
void put(int x,int y)
{
num++; e[num].x=x; e[num].t=y; du[y]++;
e[num].ne=v[x]; v[x]=num;
}
int main()
{
int n;
scanf("%d",&n);
for (int i=1;i<=n;i++) { int x; scanf("%d",&x); put(i,x); }
for (int i=1;i<=n;i++) { int x; scanf("%d",&x); put(i+n,x); }
n<<=1;
int h=0,w=0;
for (int i=1;i<=n;i++) if (du[i]==0) q[++w]=i;
while (h!=w)
{
int x=q[++h]; vis[x]=1;
for (int i=v[x];i;i=e[i].ne)
{
int y=e[i].t;
if (vis[y]==0)
{
vis[y]=2;
for (int j=v[y];j;j=e[j].ne)
{
int z=e[j].t;
du[z]--; if (du[z]==0) q[++w]=z;
}
}
}
}
n>>=1; for (int i=1;i<=n;i++) if (vis[i]==0) vis[i]=1;
n<<=1; for (int i=1;i<=n;i++) if (vis[i]==1) printf("%d ",i);
printf("\n");
return 0;
}