思路:一個點選,相關的點也必須選就是直白的2-sat模型。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000005;
const int maxm = 1000005;
int he[maxn],ver[maxm],ne[maxm],tot;
void add( int x,int y ){
ver[++tot] = y;
ne[tot] = he[x];
he[x] = tot;
}
int st[maxn],ins[maxn],c[maxn],dfn[maxn],low[maxn],top,num,cnt;
vector<int> scc[maxn];
void tarjan( int x ){
dfn[x] = low[x] = ++num;
st[++top] = x;ins[x] = 1;
for( int cure = he[x];cure;cure = ne[cure] ){
int y = ver[cure];
if( !dfn[y] ){
tarjan(y);
low[x] = min( low[x],low[y] );
}else if( ins[y] ){
low[x] = min( low[x],dfn[y] );
}
}
if( dfn[x] == low[x] ){
cnt++;int cur;
do{
cur = st[top--];ins[cur] = 0;
c[cur] = cnt;scc[cnt].push_back(cur);
}while(x != cur);
}
}
void init(int n){
top = num = cnt = 0;
memset( dfn,0,sizeof(int)*(n+1) );
for( int i = 1;i <= n;i++ ) scc[i].clear();
}
int main(){
int T;
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
tot = 1;
memset( he,0,sizeof(int)*(n+1) );
init(n);
for( int x,y,i = 1;i <= m;i++ ){
scanf("%d%d",&x,&y);
add(x,y);
}
for( int i = 1; i <= n;i++ ){
if(!dfn[i])
tarjan(i);
}
if( cnt == 1 ){
puts("No");
continue;
}
puts("Yes");
printf("%d %d\n",scc[1].size(),n-scc[1].size());
for( int i = 0;i < scc[1].size();i++ ){
printf("%d ",scc[1][i]);
}
puts("");
for( int i = 2;i <= cnt;i++ ){
for( int j = 0;j < scc[i].size();j++ ){
printf("%d ",scc[i][j]);
}
}
puts("");
}
return 0;
}