[CF1368E] Ski Accidents(神仙结论构造)

problem

CF1368E Ski Accidents

solution

这个 4 7 n \frac 47n 74n 的限制,提示这存在一个特定构造方案,由 7 7 7 我们联想到 1 + 2 + 4 = 7 1+2+4=7 1+2+4=7

暗示把顶点分为三类 A , B , C A,B,C A,B,C,满足 ∣ C ∣ ≤ 2 ∣ B ∣ ≤ 4 ∣ A ∣ |C|\le 2|B|\le 4|A| C2B4A

此时 C C C 组的元素数目一定 ≤ 4 7 n \le \frac{4}{7}n 74n

  • 构造方式:把所有入度为 0 0 0 的点都放入 A A A,把至少有一条入边来自 A A A ,但没有来自 B B B 的入边的点放入 B B B。然后,把至少有一条入边来自 B B B 的入边的点放入 C C C。剩下的点(所有入边都来 C C C )放入 A A A

此时,各类包含的顶点要求为:

  • A : A: A: 入度为 0 0 0;所有入边都来自 C C C
  • B : B: B: 至少有一条入边来自 A A A,但没有来自 B B B 的入边。
  • C : C: C: 至少有一条入边来自 B B B

不难发现,三类形成了一个有效的集合划分。

且因为每个点的出度都不超过 2 2 2,即 A A A 的出边至多有 2 ∣ A ∣ 2|A| 2A 条,所以 2 ∣ A ∣ ≥ ∣ B ∣ 2|A|\ge |B| 2AB 2 ∣ B ∣ ≥ ∣ C ∣ 2|B|\ge |C| 2BC 同理。

此时将 C C C 类点尽数删除。

由于 A , B A,B A,B 都没有来自 B B B 的入边,而 A A A 内部点之间也不存在边,所以一定不存在长度超过 1 1 1 的路径。

有向无环图,所以可以在 O ( n ) O(n) O(n) 的时间内完成求解。

code

#include <bits/stdc++.h>
using namespace std;
#define maxn 200005
vector < int > G[maxn], ans;
int T, n, m;
int col[maxn];

int main() {
	scanf( "%d", &T );
	while( T -- ) {
		scanf( "%d %d", &n, &m );
		for( int i = 1;i <= n;i ++ ) G[i].clear(), col[i] = 0;
		for( int i = 1, u, v;i <= m;i ++ ) {
			scanf( "%d %d", &u, &v );
			G[v].push_back( u );
		}
		for( int v = 1;v <= n;v ++ )
			for( int u : G[v] ) {
				if( col[u] == 1 )
					col[v] = 2;
				if( col[v] ^ 2 and col[u] == 0 )
					col[v] = 1;
			}
		ans.clear();
		for( int i = 1;i <= n;i ++ )
			if( col[i] == 2 ) ans.push_back( i );
		printf( "%d\n", ans.size() );
		for( int i : ans ) printf( "%d ", i );
		puts("");
	}	
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值