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;
}