题解 CF1037E
题解 CF1037E
题意
\(n\) 个点的图,给定 \(k\) ,初始没有边,然后依次加入 \(m\) 条无向边,在每次加边后你都要求出一个最大的点集 \(S\) ,使得这张图在仅保留 \(S\) 中点的前提下所有点度数不小于 \(k\) ,你只需要给出 \(S\) 的最大大小。
\(2\le n\le 2\times 10^5,1\le m\le 2\times 10^5,1\le k<n\) 。
题解
被卡了很久,果然脑子锈掉了。
想出做法又调了很久细节,果然脑子傻掉了。
正着想哪些点可以保留很难,考虑反正想——哪些点不能存在。
哪些点不能存在很好想,就是度数小于 \(k\) 的一定不行,然后删掉这些点再去看有没有新点度数小于 \(k\) ,这个用队列类似拓扑排序去做就行了。
加边不好搞,同样反着来,删边就行了。
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ch() getchar()
#define pc(x) putchar(x)
using namespace std;
template<typename T>void read(T&x){
static char c;static int f;
for(f=1,c=ch();c<'0'||c>'9';c=ch())if(c=='-')f=-f;
for(x=0;c>='0'&&c<='9';c=ch()){x=x*10+(c&15);}x*=f;
}
template<typename T>void write(T x){
static char q[64];int cnt=0;
if(x==0)return pc('0'),void();
if(x<0)pc('-'),x=-x;
while(x)q[cnt++]=x%10+'0',x/=10;
while(cnt--)pc(q[cnt]);
}
const int maxn=200005,maxm=200005;
int d[maxn];
struct Edge{
int v,nt;
Edge(int v=0,int nt=0):
v(v),nt(nt){}
}e[maxm*2];
int hd[maxn],num=1,dl[maxm];
void qwq(int u,int v){
e[++num]=Edge(v,hd[u]),hd[u]=num;
}
int k,q[maxn];
int Ans[maxm],X[maxm],Y[maxm];
int fro,bac;
void Down(int u){
if((--d[u])==k-1)
q[bac++]=u;
}
void cle(void){
while(fro<bac){
int u=q[fro++];d[u]=0;
for(int i=hd[u];i;i=e[i].nt){
if(dl[i>>1])continue;
dl[i>>1]=true;
int v=e[i].v;
Down(v);
}
}
}
int main(){
int n,m;
read(n),read(m),read(k);
for(int i=1;i<=m;++i){
int x,y;read(x),read(y);
qwq(x,y);qwq(y,x);
++d[x],++d[y];
X[i]=x,Y[i]=y;
}
for(int i=1;i<=n;++i)
if(d[i]<k)q[bac++]=i;
cle();
for(int i=m;i>=1;--i){
Ans[i]=n-bac;
if(!dl[i]){
Down(X[i]);
Down(Y[i]);
dl[i]=true;
cle();
}
}
for(int i=1;i<=m;++i)
write(Ans[i]),pc('\n');
return 0;
}