正难则反。动态加边比较难以维护,考虑倒着维护
先把全部边都添加的状态维护好,之后倒着删边。
对于每一次,如果有一个人他没有k个好友,那么他就永远不可能旅游,因此将他删除后,并且用一个队列来做因为他删除而导致的一系列后果。
那么还在的人是都可以去旅游的,因为他们都有k个好友
因此我们每次删一条边就把两端点做一遍上述操作,因为所有的影响都是由这两端点产生,所以我们做完了所有状态
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10; int st[N]; set<int> s[N]; int n,m,k; struct node{ int a,b; }e[N]; int in[N]; int ans[N]; int cnt; void solve(int u){ if(in[u]>=k||st[u]) return ; st[u]=1; cnt--; queue<int> q; q.push(u); while(q.size()){ auto t=q.front(); q.pop(); for(auto x:s[t]){ in[x]--; if(in[x]<k&&!st[x]){ st[x]=1; q.push(x); cnt--; } } } } int main(){ ios::sync_with_stdio(false); cin>>n>>m>>k; int i; for(i=1;i<=m;i++){ int a,b; cin>>a>>b; e[i]={a,b}; in[a]++; in[b]++; s[a].insert(b); s[b].insert(a); } cnt=n; for(i=1;i<=n;i++){ solve(i); } ans[m]=cnt; for(i=m;i>=1;i--){ int a=e[i].a,b=e[i].b; if(!st[b]) in[a]--; if(!st[a]) in[b]--; s[b].erase(a),s[a].erase(b); solve(a);solve(b); ans[i-1]=cnt; } for(i=1;i<=m;i++){ cout<<ans[i]<<endl; } }View Code