suxxsfe

一言(ヒトコト)

P5361 [SDOI2019]热闹的聚会与尴尬的聚会

https://www.luogu.com.cn/problem/P5361

见了好几次这个题了
考虑第一问怎么求 \(p\) 的最大值
从度数最小的点开始删,每次删完更新相邻点的度,直到删完为止
那么每次删的时候这个度数最小的点的度数最大值,就是 \(p\)

加上第一问,变化一下那个式子发现是 \((p+1)(q+1)\ge n\)
设每次删的时候找到的那个度数最小的点度数分别是 \(d_i\),那么他和他相邻的点共有 \(d_i+1\) 个,而 \(p=\max d_i\)
所以只要把这个度数最小的点选入第二个集合中,然后把相邻的点全部删掉就行了
因为 \(\sum_{i=1}^q (d_i+1)=n\),所以必然有 \((\max d_i +1)(q+1)\ge n\)

#define N 10006
#define M 200006
struct Graph{
	int fir[N],nex[M],to[M],tot;
	inline void add(int u,int v,int flag=1){
		to[++tot]=v;nex[tot]=fir[u];fir[u]=tot;
		if(flag) add(v,u,0);
	}
	inline void clear(){std::memset(fir,0,sizeof fir);tot=0;}
}G;
int n,m;
int in[N],ans[N],del[N];
inline int cmp(const int &a,const int &b){return in[a]==in[b]?a<b:in[a]<in[b];}
std::set<int,int(*)(const int &a,const int &b)>set(cmp);
int main(){
//		freopen("party3.in","r",stdin);
int $=read();while($--){
	n=read();m=read();
	for(int u,v,i=1;i<=m;i++) u=read(),v=read(),in[u]++,in[v]++,G.add(u,v);
	for(int i=1;i<=n;i++) set.insert(i);
	int o=0,maxp=0,id;
	while(!set.empty()){
		int u=*set.begin();set.erase(u);
		del[u]=++o;ans[++ans[0]]=u;
		if(in[u]>maxp) maxp=in[u],id=o;
		for(int v,i=G.fir[u];i;i=G.nex[i]){
			v=G.to[i];
			if(del[v]) continue;
			del[v]=o;set.erase(v);
			for(int j=G.fir[v];j;j=G.nex[j])if(!del[G.to[j]]) set.erase(G.to[j]),in[G.to[j]]--,set.insert(G.to[j]);
		}
	}
	o=0;
//		printf(">>>%d\n",maxp);
	for(int i=1;i<=n;i++) o+=del[i]>=id;
	writeSP(o);
	for(int i=1;i<=n;i++)if(del[i]>=id) writeSP(i);EN;
	writeSP(ans[0]);
	for(int i=1;i<=ans[0];i++) writeSP(ans[i]);EN;
	set.clear();std::memset(ans,0,sizeof ans);
	G.clear();std::memset(del,0,sizeof del);std::memset(in,0,sizeof in);
}
	return RET;
}
posted @ 2022-02-24 15:04  suxxsfe  阅读(22)  评论(0编辑  收藏  举报