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]?aset(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;
}