题解 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;
}
posted @ 2022-07-28 15:08  xiaolilsq  阅读(54)  评论(0编辑  收藏  举报