版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
传送门
题解:
其实仔细看一下发现是要使得 ,并且 两个集合互不相关。
那么其实问题就是找一个尽可能大的独立集(众所周知最大独立集是NP-Hard)和一个最小度数尽可能大的子图。
第一反应:这怎么没有输出-1???一定有解???
确实是一定有解。
我在LOJ提交记录里面看到了好多乱搞,比如说什么随机化,还有用bitset的。。。
典型乱搞题你值得拥有
实际上这道题有复杂度稳定的且保证解正确的高效做法。
首先求一个极大独立集,我们考虑如下方式:
每次从残余子图中选择一个度数最小的点,把它和它相邻的所有点删除,设它的度数为 ,则这次会删除 个点,当前图中最小度数就是 。
找到最大的 ,所有该时刻后删除的点全部加到 集合中,所有作为最小度数被选择过的点加入 集合,显然这个时候 ,且由于每次至多删除 个点,有 ,满足题意。
找度数最小的点我写的ZKW线段树。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=1e4+7,M=1e5+7;
int n,m,tim,mx;
int d[N],del[N],vis[N];
std::vector<int> G[N];
namespace SGT{
int a[1<<15|7],M;
inline int Min(int a,int b){return d[a]<d[b]?a:b;}
inline void init(int n){
for(M=1;M<=n+1;M<<=1);
for(int re i=M;i<=M+M-1;++i)a[i]=(1<=i-M&&i-M<=n)?i-M:0;
for(int re i=M-1;i;--i)a[i]=Min(a[i<<1],a[i<<1|1]);
}
inline void update(int p){for(p+=M;p>>=1;)a[p]=Min(a[p<<1],a[p<<1|1]);}
inline int top(){return a[1];}
}
inline void solve(){
n=gi(),m=gi();
memset(d+1,0,n<<2);
memset(del+1,0,n<<2);
memset(vis+1,0,n<<2);
for(int re i=1;i<=n;++i)G[i].clear();
for(int re i=1;i<=m;++i){
int u=gi(),v=gi();
++d[u],++d[v];
G[u].push_back(v);
G[v].push_back(u);
}
SGT::init(n);tim=mx=0;int ps=0;
while(true){
int u=SGT::top();if(d[u]==1e9)break;
if(d[u]>=mx)mx=d[u],ps=tim;
vis[u]=1;del[u]=++tim,d[u]=1e9,SGT::update(u);
for(int re v:G[u])if(!del[v]){
del[v]=tim;d[v]=1e9,SGT::update(v);
for(int re w:G[v])if(!del[w])--d[w],SGT::update(w);
}
}
std::vector<int> P,Q;
for(int re i=1;i<=n;++i){
if(del[i]>ps)P.push_back(i);
if(vis[i])Q.push_back(i);
}
cout<<P.size()<<"\n";
for(int re u:P)cout<<u<<" ";cout<<"\n";
cout<<Q.size()<<"\n";
for(int re v:Q)cout<<v<<" ";cout<<"\n";
}
signed main(){
#ifdef zxyoi
freopen("party.in","r",stdin);
#endif
d[0]=1e9;int T=gi();while(T--)solve();
return 0;
}