NOIAC#110. 翘课 拓扑

NOIAC#110. 翘课

题目传送门

分析

考虑如果给你一张图,怎么判断最大?
首先度数不足 K K K的节点肯定都不能选。
把它们从图中删去,剩下的图中如果还有度数不足 K K K的继续删掉。
用这样一个类似拓扑的过程,最后剩下的那张图肯定是最大的合法的答案。
那么如果有加边操作呢?
考虑上面的过程,其实一直在删点删边。
所以考虑离线倒序,删边判合法即可。

代码

注意已经删除的边的影响。

#include<bits/stdc++.h>
const int N = 4e5 + 10;
int ri() {
	char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
	for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int L, R, tp, k, n, m, cr, C, U[N], V[N], q[N], d[N], to[N], nx[N], pr[N], Ans[N]; 
void add(int u, int v) {to[++tp] = v; nx[tp] = pr[u]; pr[u] = tp;}
void adds(int u, int v) {add(u, v); add(v, u); ++d[v]; ++d[u];}
void Dec(int x) {if(--d[x] < k) q[++R] = x;}
void Bfs() {
	for(int u = q[L];L <= R; u = q[++L]) 
		for(int i = pr[u]; i; i = nx[i])
			if((i + 1 >> 1) < C && d[to[i]] >= k)
				Dec(to[i]);
}
int main() {
	n = ri(); m = ri(); k = ri();
	cr = n; L = 1; R = 0;
	for(int i = 1;i <= m; ++i) U[i] = ri(), V[i] = ri(), adds(U[i], V[i]);
	for(int i = 1;i <= n; ++i) 
		if(d[i] < k) 
			q[++R] = i;
	C = m + 1; Bfs();
	for(C = m; C; --C) {
		Ans[C] = n - R;
		int u = U[C], v = V[C];
		if(d[u] >= k && d[v] >= k) 
			Dec(u), Dec(v);
		Bfs();
	}
	for(int i = 1;i <= m; ++i) 
		printf("%d\n", Ans[i]);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值