[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;
}