CodeForces 1361E James and the Chase
https://codeforces.com/contest/1361/problem/E
Tutorial
https://codeforces.com/blog/entry/78355
考虑对于一个点如何判断它是否为interesting的.
以它为根建立dfs树,发现它为interesting的条件就是dfs树上没有横叉边.
由于20%的限制,我们可以随机(T=100)次,这样就可以找到某个interesting的点(r),或判断其小于20%.
以(r)为根建立dfs树,现在树上只有返祖边和树边.考虑怎样的点是interesting的.
考虑树上不是(r)的某个点(u),那么发现条件为(u)到它的所有祖先都只有一条简单路径,那么如果(u)子树中有大于1个连向(u)的祖先的边,那么(u)一定不合法.由于这是一个强连通分量,所以至少也存在一条边,设其连向(v),那么根据刚才的条件,可以递归的发现,(u)合法的条件就是(v)合法.
复杂度(O(Tn))
Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
inline char gc() {
// return getchar();
static char buf[100000],*l=buf,*r=buf;
return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
}
template<class T> void rd(T &x) {
x=0; int f=1,ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
x*=f;
}
typedef unsigned long long ull;
const int inf=1e9;
const int maxn=1e5+50;
int t,n,m;
int head[maxn];
int dep[maxn],tag[maxn],mn[maxn];
bool mark[maxn],vis[maxn];
bool good[maxn];
struct edge {
int to,nex;
edge(int to=0,int nex=0):to(to),nex(nex){}
};
vector<edge> G;
inline void addedge(int u,int v) {
G.push_back(edge(v,head[u])),head[u]=G.size()-1;
}
inline ull Rand() {
static ull seed=0;
seed^=rand();
seed^=seed<<13;
seed^=seed>>17;
seed^=seed<<5;
return seed;
}
bool dfs0(int u) {
vis[u]=mark[u]=1;
for(int i=head[u];~i;i=G[i].nex) {
int v=G[i].to;
if(!vis[v]) {
if(!dfs0(v)) return 0;
}
else {
if(!mark[v]) return 0;
}
}
mark[u]=0;
return 1;
}
void dfs1(int u) {
vis[u]=1;
mn[u]=u;
for(int i=head[u];~i;i=G[i].nex) {
int v=G[i].to;
if(!vis[v]) {
dep[v]=dep[u]+1;
dfs1(v);
tag[u]+=tag[v];
if(dep[mn[v]]<dep[mn[u]]) mn[u]=mn[v];
}
else {
++tag[u],--tag[v];
if(dep[v]<dep[mn[u]]) mn[u]=v;
}
}
if(tag[u]<=1) good[u]=1;
}
void dfs2(int u) {
vis[u]=1;
if(mn[u]!=n+1) good[u]&=good[mn[u]];
for(int i=head[u];~i;i=G[i].nex) {
int v=G[i].to;
if(!vis[v]) dfs2(v);
}
}
bool check(int x) {
for(int i=1;i<=n;++i) mark[i]=vis[i]=0;
return dfs0(x);
}
void sol(int r) {
for(int i=1;i<=n;++i) vis[i]=0;
dep[r]=0,dfs1(r);
for(int i=1;i<=n;++i) vis[i]=0;
dfs2(r);
}
void clear() {
G.clear();
for(int i=1;i<=n;++i) {
head[i]=-1;
good[i]=tag[i]=0;
}
}
int main() {
srand((ull)(new char));
rd(t);
memset(head,-1,sizeof(head));
for(int kase=1;kase<=t;++kase) {
clear();
rd(n),rd(m);
for(int i=1;i<=m;++i) {
int u,v; rd(u),rd(v);
addedge(u,v);
}
int T=100,r=-1; while(T--) {
r=Rand()%n+1;
if(check(r)) break;
r=-1;
}
if(r==-1) {puts("-1"); continue;}
sol(r);
vector<int> an;
for(int i=1;i<=n;++i) if(good[i]) an.push_back(i);
if(an.size()*5<n) puts("-1");
else {
for(int i=0;i<an.size();++i) {
if(i) printf(" ");
printf("%d",an[i]);
}
printf("
");
}
}
return 0;
}