一个经验是,这种询问两种有些互斥的情况的构造题,往往都是有解的,CF出过很多类似题,特别是给定了一些奇怪的点数,例如倍数之类的
往往一种情况取反就是另一种情况,以前有些dfs树上找环也是这种题,不过更难一些
话说回来,对于这题,我们可以考虑在加边的时候,对于边两端,如果两个点都没标记过,就标记一下,并把它放入边独立集。做完后没被标记的就是点独立集。
基于的原理是,首先边独立集显然是正确的,其次,假设剩下的有两个未被标记的点直接存在边,那么他一定会在之前的操作中被列入边独立集。因此剩下的都是点独立集
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<ll,ll> pll; const int N=5e5+10; const int M=2e6+10; const int inf=0x3f3f3f3f; int st[N]; int ans[N]; int main(){ ios::sync_with_stdio(false); int t; cin>>t; while(t--){ int n,m; cin>>n>>m; int i; int cnt=0; for(i=1;i<=3*n;i++) st[i]=0; for(i=1;i<=m;i++){ int a,b; cin>>a>>b; if(!st[a]&&!st[b]){ ans[++cnt]=i; st[a]=st[b]=1; } } if(cnt<=n){ cout<<"IndSet"<<endl; int id=0; for(i=1;i<=3*n;i++){ if(!st[i]){ cout<<i<<" "; id++; } if(id==n){ break; } } } else{ cout<<"Matching"<<endl; for(i=1;i<=n;i++) cout<<ans[i]<<" "; cout<<endl; } } }