题意:给出n点,m边的森林,a[i]为i的祖先,问能否构造出一个list,使得每个i:在list中第一个找到的祖先为a[i]?
i的祖先集合为B,则在list中,a[i]应该出现在每个b[k]之前,a[i]->b[k]连接一条边,判断拓扑序.(显然MLE,TLE!!)
u-v v为u的father
情况1:u给u送礼
情况2:u不给自己送礼,则list中:a[v]要出现在a[u]之前,a[u]也要出现在a[v]之前,要想合法只有a[v]==a[u]
即a[u]==u||a[u]=a[v]
构造解:当合法时,若a[u]!=u,则u不会出现在list中.
若有x=son(u) && a[x]=u 因为若a[x]=u 则u肯定只能给自己送礼 即a[u]=u,矛盾
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e6+20;
const ll inf=2e15;
vector<int> ans;
bool flag,rt[N];
int n,m,a[N],in[N];
int fa[N];
vector<int> e[N];
void dfs(int u)
{
if(!flag)
return;
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];//
if(a[v]!=v&&a[u]!=a[v])
{
flag=false;
return;
}
dfs(v);
}
//子树判断完以后
if(a[u]==u)
ans.push_back(u);
}
int main()
{
while(cin>>n>>m)
{
int u,v;
flag=true;
memset(in,0,sizeof(in));
memset(rt,true,sizeof(rt));
ans.clear();
for(int i=0;i<m;i++)
{
scanf("%d%d",&u,&v);
e[u].push_back(v);
rt[v]=false;
}
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
//从根开始
if(rt[i])
dfs(i);
}
if(!flag)
puts("-1");
else
{
cout<<ans.size()<<endl;
for(int i=0;i<ans.size();i++)
cout<<ans[i]<<endl;
}
}
return 0;
}