Manthan, Codefest 18 (rated, Div. 1 + Div. 2) F Trips(Set)

Description:

有n个人,在m天内这些人可能会去旅行。这些人有毒,对于每个人来说每天要不就不去旅行,要不就是自己认识的至少K个人去旅行自己才跟着去。

起初每个人互相不认识,之后的m天里,每一天早上都会有两个人互相认识。

现在问从1到m天内,每一天最多有多少人去旅行。(“认识”这一关系没有传递性)

Input:

n,m,K

ui,vi(1<=i<=m) 表示在第i天ui和vi这两个人互相认识了

Output:

maxi(1<=i<=m)表示第i天的答案

Analysis:

这一题的图论背景是显然的,实际上是指有m个边依次加入,问每次加入边后, 满足所有点的度数都大于等于K的子图里最大的点数为多少。

这样的关系从正面做想不到什么好办法,并不能知道一个点的度数以及其邻接点度数是否都>=K。但是从反面想就自然了,可以考虑在这些点中,不符合条件的点(度数小于K),把这样的点从中删去,然后对于它的所有邻接点,度数都减一,然后再继续。这样一直操作到不能继续下去的时候,剩下的点就都是符合条件的了。

有了这样的想法后,就可以维护一个set,里面存储pair<点的度数,点的id>,这样就可以每次取出set的第一个元素操作,直到第一个元素的度数>=K或者set为空为止。然后整个set的size就是某一天的答案。

但是,这里要是每次都把所有的点都放进一个新的set,然后一个一个删去来做的话会超时。其实可以从一开始就把所有的点都放入set中,然后按照逆序删去边倒着来做。维护信息时要注意别重复删去度数。1.若某一条边中的一个点已经不再set中了,就跳过这条边不考虑,因为之前考虑过了 2.若当前考虑的点在这一天之后才加入set的,同样之前就已经考虑过了, 也直接跳过

#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<sstream>
#include<cmath>
#include<iterator>
#include<bitset>
#include<stdio.h>
#include<ctime>
#include<cstring>
#include<string>
#include<float.h>
#include<stack>
#include<unordered_map>
using namespace std;
#define _for(i,a,b) for(int i=(a);i<(b);++i)
#define _rep(i,a,b) for(int i=(a);i<=(b);++i)
typedef long long LL;
const int INF = 1<<30;
const int MOD = 998244353;
const int maxn = 200005;

int n, m, K;
multiset<pair<int, int> > se;
multiset<pair<int, int> >::iterator pos[maxn];
vector<pair<int,int> > G[maxn];
pair<int,int> edges[maxn];
int deg[maxn];
bool inse[maxn];
int main()
{

	while (~scanf("%d%d%d", &n, &m, &K)) {
		se.clear();
		memset(deg, 0, sizeof(deg));
		memset(pos, 0, sizeof(pos));
		memset(inse, 0, sizeof(inse));
		for (int i = 1; i <= n; ++i)G[i].clear();
		_rep(i, 1, m) {
			scanf("%d%d", &edges[i].first, &edges[i].second);
			deg[edges[i].first]++; deg[edges[i].second]++;
			G[edges[i].first].push_back({ edges[i].second,i });
			G[edges[i].second].push_back({ edges[i].first,i });
		}
		for (int i = 1; i <= n; ++i) {
			se.insert({ deg[i],i });
			inse[i] = 1;
		}
		while (se.size() && se.begin()->first < K) {
			int u = se.begin()->second;
			se.erase(se.begin());
			inse[u] = 0;
			for (auto & it : G[u]) {
				int v = it.first;
				if (inse[v]) {
					se.erase({ deg[v],v});
					deg[v]--;
					se.insert({ deg[v],v });
				}
			}
		}
		vector<int> ans(m+1);
		for (int i = m; i >= 1; --i) {
			ans[i] = se.size();
			int u = edges[i].first, v = edges[i].second;
			if (inse[u] && inse[v]) {
				se.erase({ deg[u],u }); se.erase({ deg[v],v });
				deg[u]--; deg[v]--;
				se.insert({ deg[u],u }); se.insert({ deg[v],v });
			}
			while (se.size() && se.begin()->first < K) {
				int u = se.begin()->second;
				se.erase(se.begin());
				inse[u] = 0;
				for (pair<int,int> & it : G[u]) {
					int v = it.first;
					if (it.second >= i)
						continue;
					if (inse[v]) {
						se.erase({ deg[v],v });
						deg[v]--;
						se.insert({ deg[v],v });
					}
				}
			}
		}
		_rep(i, 1, m)printf("%d\n", ans[i]);
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/tomandjake_/article/details/82384035