[CF1463E] Plan of Lectures

[CF1463E] Plan of Lectures - 拓扑排序,并查集

Description

构造一个 1..n 的排列,有一些限制:指定了一些 (ai,i) 要求 ai 出现在 i 的前面,指定了一些 (i,j) 要求 i 一定在 j 之前一个位置

Solution

先考虑第二类条件,用类似并查集的方法来串串,最后我们把一个点往后几个固定的点都找出来,同时判断是否有环路

接下来缩点(选取链头作为代表点)然后跑拓扑排序

跑完拓扑以后,我们把得到的序列展开(缩点还原),然后检查一遍所有条件是否满足即可

(第一遍写的时候把两种条件看反了)

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 1000005;
int n, m;
int fa[N];
pair<int, int> e[N];
vector<int> toposeq;
vector<int> g[N];
int vis[N], ind[N];
list<int> ls[N];
vector<int> seq;
int a[N];

int find(int p)
{
    return p == fa[p] ? p : fa[p] = find(fa[p]);
}

void dfs(int p)
{
    vis[p] = 1;
    for (auto q : g[p])
        if (vis[q] == 0)
        {
            dfs(q);
        }
    toposeq.push_back(p);
}

signed main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
        fa[i] = i, ls[i].push_back(i);
    for (int i = 1; i <= n; i++)
    {
        cin >> a[i];
    }
    for (int i = 1; i <= m; i++)
    {
        int u, v;
        cin >> u >> v;
        int p = find(u), q = find(v);
        if (p == q)
        {
            cout << 0 << endl;
            return 0;
        }
        else
        {
            fa[q] = p;
            ls[p].splice(ls[p].end(), ls[q]);
        }
    }
    for (int i = 1; i <= n; i++)
    {
        if (a[i] == 0)
            continue;
        int u = a[i], v = i;
        e[i] = {u, v};
        if (find(u) == find(v))
            continue;
        g[find(u)].push_back(find(v));
        ind[find(v)]++;
    }
    for (int i = 1; i <= n; i++)
        if (ind[i] == 0 && find(i) == i)
            dfs(i);
    reverse(toposeq.begin(), toposeq.end());
    for (auto p : toposeq)
    {
        for (auto i : ls[p])
        {
            seq.push_back(i);
        }
    }
    vector<int> inv(n + 2);
    for (int i = 0; i < seq.size(); i++)
        inv[seq[i]] = i;
    for (int i = 1; i <= n; i++)
    {
        if (a[i] == 0)
            continue;
        int u = a[i], v = i;
        if (inv[v] < inv[u])
        {
            cout << 0 << endl;
            return 0;
        }
    }
    if (seq.size() == 0)
    {
        cout << 0 << endl;
        return 0;
    }
    for (int i = 0; i < seq.size(); i++)
        cout << seq[i] << " ";
    cout << endl;
}
原文地址:https://www.cnblogs.com/mollnn/p/14474656.html