cf 1037E Trirps
给一幅图,边从0开始每天多一条边,问每天增加边之后能够有多少人去旅游。
能去旅游的定义是只有当联通的点的度数都大于才能去旅游,否则都不能去旅游。
考虑从后往前遍历删边,当有点的度数小于k时将这个点从图中删去并把它的边删去。
#include <bits/stdc++.h> using namespace std; #define mp make_pair #define pb push_back const int M = 2e5+7; int n,m,k,tmp; int ans[M],exist[M],deg[M]; vector<int> g[M]; pair<int,int> e[M]; queue<int> q; void solve(){ while(!q.empty()){ int u=q.front();q.pop(); if(!exist[u]) continue; exist[u]=0;tmp--; for(int i=0;i<g[u].size();i++){ int v=g[u][i]; if(exist[v]){ deg[v]--; if(deg[v]<k){ q.push(v); } } } } } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=m;i++){ int u,v; scanf("%d%d",&u,&v); g[u].pb(v); g[v].pb(u); e[i]=mp(u,v);//存边 deg[u]++;deg[v]++;//度数++ } tmp=n; memset(exist,1,sizeof(exist)); for(int i=1;i<=n;i++) if(deg[i]<k){//把度数小于k的推进队列 q.push(i); } solve();//把队列中的点及点连的边从图中删去 for(int i=m;i>=1;i--){//从后向前删边 ans[i]=tmp; int u=e[i].first,v=e[i].second; g[u].pop_back();g[v].pop_back(); if(exist[u]&&exist[v]){ deg[u]--;deg[v]--; if(deg[u]<k){ q.push(u); } if(deg[v]<k){ q.push(v); } } solve(); } for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }