CodeForces 1361E James and the Chase

CodeForces 1361E James and the Chase

https://codeforces.com/contest/1361/problem/E

Uthgcd.png

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("\n");
		}
	}
	return 0;
} 
posted @ 2020-07-14 09:39  LJZ_C  阅读(198)  评论(0编辑  收藏  举报