题解 有向图

传送门
CF1361E

首先发现那个 \(20\%\) 的条件很奇怪
貌似可以随机化找到一个有趣的点,再利用这个点去找别的点
发现从这个点开始dfs得到的dfs树上仅有树边和返祖边
于是一个点无趣的条件是同时在超过一个环中或其子树内存在一条连向一个无趣点的返祖边

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define pb push_back
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int head[N], size;
struct edge{int to, next, rk;}e[N<<1];
inline void add(int s, int t) {e[++size]={t, head[s]}; head[s]=size;}

namespace force{
	bool vis[N], anc[N];
	int ans[N], top;
	bool dfs(int u) {
		anc[u]=vis[u]=1;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (anc[v]) continue;
			if (vis[v]) return 0;
			if (!dfs(v)) return 0;
		}
		anc[u]=0;
		return 1;
	}
	void solve() {
		top=0;
		for (int i=1; i<=n; ++i) {
			// cout<<"i: "<<i<<endl;
			for (int j=1; j<=n; ++j) vis[j]=anc[j]=0;
			if (dfs(i)) ans[++top]=i;
		}
		for (int i=1; i<=top; ++i) printf("%d%c", ans[i], " \n"[i==top]);
	}
}

namespace task1{
	vector<int> to[N];
	int in[N], bit[N], bit2[N], res[N], siz[N], sum[N], rot, tot, qsiz;
	bool vis[N], anc[N], disable[N], ans[N];
	struct que{int l, r, rk;};
	vector<que> q[N];
	inline void upd(int i, int dat) {for (; i<=n; i+=i&-i) bit[i]+=dat;}
	inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
	inline void upd2(int i, int dat) {for (; i<=n; i+=i&-i) bit2[i]+=dat;}
	inline int query2(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit2[i]; return ans;}
	bool dfs1(int u) {
		anc[u]=vis[u]=1;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (anc[v]) continue;
			if (vis[v]) return 0;
			if (!dfs1(v)) return 0;
		}
		anc[u]=0;
		return 1;
	}
	int getrt() {
		for (int i=1; i<=n; ++i) disable[i]=0;
		while (1) {
			int t;
			do {t=rand()%n+1;} while (disable[t]);
			for (int i=1; i<=n; ++i) vis[i]=anc[i]=0;
			if (dfs1(t)) return t;
			else disable[t]=1;
		}
	}
	void dfs2(int u) {
		// cout<<"dfs2: "<<u<<endl;
		in[u]=++tot;
		siz[u]=1; anc[u]=1;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (!anc[v]) dfs2(v), siz[u]+=siz[v];
		}
		anc[u]=0;
	}
	void dfs3(int u) {
		anc[u]=1;
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (!anc[v]) dfs3(v);
			else to[v].pb(u), q[v].pb({in[u], in[u]+siz[u]-1, e[i].rk=++qsiz});
		}
		anc[u]=0;
	}
	void dfs4(int u) {
		anc[u]=1;
		sum[u]=query(in[u]+siz[u]-1)-query(in[u]-1);
		if (sum[u]>1) ans[u]=1;
		if (query2(in[u]+siz[u]-1)-query2(in[u]-1)) ans[u]=1;
		for (auto it:q[u]) res[it.rk]=query(it.r)-query(it.l);
		for (auto it:to[u]) upd(in[it], 1); //, cout<<"at: "<<u<<' '<<it<<' '<<1<<endl;
		if (ans[u]) for (auto it:to[u]) upd2(in[it], 1);
		for (int i=head[u],v; ~i; i=e[i].next) {
			v = e[i].to;
			if (!anc[v]) dfs4(v);
			else if (sum[v]>1) {
				// cout<<"dfs4: "<<u<<' '<<v<<' '<<e[i].rk<<endl;
				// if (sum[v]-res[e[i].rk] > 1) ans[u]=1;
				ans[u]=1;
			}
		}
		if (ans[u]) for (auto it:to[u]) upd2(in[it], -1);
		for (auto it:to[u]) upd(in[it], -1);
		anc[u]=0;
	}
	void solve() {
		rot=getrt(); tot=qsiz=0;
		// cout<<"rot: "<<rot<<endl;
		for (int i=1; i<=n; ++i) bit[i]=bit2[i]=sum[i]=0, to[i].clear(), q[i].clear();
		for (int i=1; i<=n; ++i) anc[i]=ans[i]=0;
		dfs1(rot); dfs2(rot); dfs3(rot); dfs4(rot);
		for (int i=1; i<=n; ++i) if (!ans[i]) printf("%d ", i); printf("\n");
		// cout<<"in: "; for (int i=1; i<=n; ++i) cout<<in[i]<<' '; cout<<endl;
		// cout<<"siz: "; for (int i=1; i<=n; ++i) cout<<siz[i]<<' '; cout<<endl;
		// for (int i=1; i<=n; ++i) {
		// 	cout<<"i: "<<i<<':';
		// 	for (auto it:to[i]) cout<<it<<' '; cout<<endl;
		// }
		// cout<<"qsiz: "<<qsiz<<endl;
		// cout<<"res: "; for (int i=1; i<=qsiz; ++i) cout<<res[i]<<' '; cout<<endl;
		// cout<<"sum: "; for (int i=1; i<=n; ++i) cout<<sum[i]<<' '; cout<<endl;
	}
}

signed main()
{
	freopen("graph.in", "r", stdin);
	freopen("graph.out", "w", stdout);

	int T=read();
	for (int k=1; k<=T; ++k) {
		n=read(); m=read(); size=0;
		// if (k==1108) cout<<n<<' '<<m<<endl;
		memset(head, -1, sizeof(int)*(n+5));
		for (int i=1,u,v; i<=m; ++i) {
			u=read(); v=read();
			// if (k==1108) cout<<u<<' '<<v<<endl;
			add(u, v);
		}
		// force::solve();
		task1::solve();
	}

	return 0;
}
posted @ 2022-01-11 20:20  Administrator-09  阅读(1)  评论(0编辑  收藏  举报