分析:
肥肠简单但却很容易想岔的题、、、(就是那种想清楚过后觉得水得不行,然而却想了半个小时的题)
首先,这题第一个坑,就是在线/离线
因为每次边是一条一条加的,这非常类似一些数据结构的特色(单一修改),所以很容易就去想在线怎么做。。。。然而我想了至少20分钟还是没个优秀的算法。。。所以就不得不考虑离线
首先要提及一点:这个题说要去的人数最大化,但其实每个人之间并没有矛盾关系,所以只要能去的人都去就行了,把这种人定义为“合法”。
加边改删边,发现这个题删边很容易实现:每次删除后,如果这两个点都是合法的,那么这两个点的度数都-1,再检查其剩下的度数是否比k小,如果是就把这个点删去,然后与它相连的点度数-1,如此递归地操作下去。
这样均摊下来的复杂度是 O(n+m) O ( n + m ) 的(每个点最多从“合法”变为“不合法”一次)。
现在问题转化为:求连完所有边后,哪些点合法?
这就是第二个坑点,如果你要检查是否合法,也是几乎不可行的。正确的姿势是:把所有度数小于k的点删去,和上面的操作几乎一模一样。这样一来,剩下的图中,每个点连的边都一定是合法的,并且度数都不小于k。所以就得到最终状态下(连完所有边后)的合法情况了。
代码是博主在考场上写的,略丑
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define SF scanf
#define PF printf
#define MAXN 200010
using namespace std;
typedef long long ll;
int n,m,k;
vector<int> a[MAXN],used[MAXN];
pair<int,int> l[MAXN];
set<pair<int,int> > st;
int d[MAXN];
bool del[MAXN];
int ansx[MAXN],ans;
void dele(int x){
del[x]=1;
ans--;
for(int i=0;i<a[x].size();i++){
int u=x,v=a[x][i];
if(u>v)
swap(u,v);
if(del[a[x][i]]==0&&st.count(make_pair(u,v))==0){
st.insert(make_pair(u,v));
d[a[x][i]]--;
if(d[a[x][i]]<k){
dele(a[x][i]);
}
}
}
}
int main(){
SF("%d%d%d",&n,&m,&k);
int u,v;
for(int i=1;i<=m;i++){
SF("%d%d",&u,&v);
a[u].push_back(v);
a[v].push_back(u);
d[u]++;
d[v]++;
l[i]=make_pair(u,v);
}
ans=n;
for(int i=1;i<=n;i++)
if(d[i]<k&&del[i]==0)
dele(i);
for(int i=1;i<=n;i++)
a[i].clear();
st.clear();
for(int i=1;i<=m;i++)
if(del[l[i].first]==0&&del[l[i].second]==0){
a[l[i].first].push_back(l[i].second);
a[l[i].second].push_back(l[i].first);
}
for(int i=1;i<=n;i++)
d[i]=a[i].size();
for(int i=m;i>=1;i--){
ansx[i]=ans;
if(del[l[i].first]==0&&del[l[i].second]==0&&st.count(make_pair(min(l[i].first,l[i].second),max(l[i].first,l[i].second)))==0){
st.insert(make_pair(min(l[i].first,l[i].second),max(l[i].first,l[i].second)));
if(d[l[i].first]>d[l[i].second])
swap(l[i].first,l[i].second);
d[l[i].first]--;
d[l[i].second]--;
if(d[l[i].first]<k)
dele(l[i].first);
if(d[l[i].second]<k&&del[l[i].second]==0)
dele(l[i].second);
}
}
for(int i=1;i<=m;i++)
PF("%d\n",ansx[i]);
}