嘘~ 正在从服务器偷取页面 . . .

CF1239D Catowice City 题解


CF1239D Catowice City 题解

题目链接:CF1239D Catowice City

题意

下周末将在卡托维兹市举行猫比赛。然而,评委成员和参赛者尚未确定。卡托维兹市有 \(n\) 名居民和 \(n\) 只猫,每个居民的家中都有一只猫。居民和猫的编号分别为 1 到 \(n\),第 \(i\) 只猫住在第 \(i\) 名居民的家中。

每个卡托维兹市的居民与几只猫交朋友,其中包括他家中的那只猫。为了举办比赛,至少需要一名评委和一名猫参赛者。当然,每个评委都不应认识任何参赛者。为了比赛的成功举办,评委人数加上参赛者人数应该等于 \(n\)

请帮助卡托维兹市的居民为即将举行的比赛选择评委和参赛者,或确定无法实现。

输入格式

第一行包含一个整数 \(t\)\(1 \leq t \leq 100000\)),表示测试用例的数量。接下来是 \(t\) 个测试用例的描述,每个描述如下:

第一行包含整数 \(n\)\(m\)\(1 \leq n \leq m \leq 10^6\)),表示卡托维兹市居民的数量和居民与猫之间的友谊对数。

接下来的 \(m\) 行中,每行包含整数 \(a_i\)\(b_i\)\(1 \leq a_i, b_i \leq n\)),表示第 \(a_i\) 名居民与第 \(b_i\) 只猫相识。保证每对居民和猫的组合最多只列出一次。

不同的测试用例之间用空行分隔。

保证所有测试用例中 \(n\) 的总和最多为 \(10^6\)\(m\) 的总和最多为 \(10^6\)

输出格式

对于每个测试用例,打印:

如果无法选择评委和参赛者,则打印 "No"。 否则打印 "Yes"。

在第二行打印两个整数 \(j\)\(p\)\(1 \leq j, 1 \leq p, j+p=n\)),表示评委成员和比赛参与者的数量。

在第三行打印 \(j\) 个从 1 到 \(n\) 的不同整数,表示组成评委团的居民的索引。

在第四行打印 \(p\) 个从 1 到 \(n\) 的不同整数,表示将参加比赛的猫的索引。 如果存在多个正确答案,则可以任意打印其中一个。

注意到每只猫都和自己的主人认识,所以我们可以把猫和自己的主人看作一个节点

则此时任意的一个强连通分量,要么全部选猫,要么全部选人。

于是我们钦定出度为 \(0\) 的那个强连通分量全部选人,然后其他点全部选猫。如果只有一个强连通分量则无解。

时间复杂度 \(\mathcal{O}(n+m)\)

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e6 + 15))

int n,m,pos=1,top,scnt,head[N],dfn[N],low[N],stk[N],sz[N],scc[N]; bitset<N> ins;
struct Edge { int u,v,next; } e[N];
void addEdge(int u,int v) { e[++pos] = {u,v,head[u]}; head[u] = pos; }
void Tarjan(int u)
{
    static int tim = 0;
    dfn[u] = low[u] = ++tim; ins[stk[++top] = u] = 1;
    for(int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].v;
        if(!dfn[v]) {
            Tarjan(v); down(low[u], low[v]);
        }else if(ins[v]) { down(low[u], dfn[v]); }
    }
    if(low[u] == dfn[u]) {
        ++scnt;
        for(int p = 0; p != u; ) {
            p = stk[top--]; scc[p] = scnt; ins[p] = 0; ++sz[scnt];
        }
    }
}
void solve()
{
    cin >> n >> m; scnt = top = 0; pos = 1;
    for(int i = 1; i <= n; i++) head[i] = sz[i] = dfn[i] = ins[i] = 0;
    for(int i = 1,u,v; i <= m; i++) { cin >> u >> v; if(u != v) addEdge(u,v); }
    for(int i = 1; i <= n; i++) if(!dfn[i]) Tarjan(i);
    // cout << "scnt = " << scnt << '\n';
    if(scnt == 1) return cout << "No" << '\n', void(0);
    cout << "Yes\n" << sz[1] << ' ' << n - sz[1] << '\n';
    for(int i = 1; i <= n; i++) if(scc[i] == 1) { cout << i << ' '; } cout << '\n';
    for(int i = 1; i <= n; i++) if(scc[i] != 1) { cout << i << ' '; } cout << '\n';
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    int Q; cin >> Q; while(Q--) solve();
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/blog/Songziqing/solution-cf1239d


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录