T2
Description
你需要构造一个长度为
其中第
Solution
首先显然的是,既然
利用这个关系,我们就可以把题目转化成另外一个题目:仍然需要构造一个长度为
考虑将其转化成图论问题。第一步,我们将所有有着相同值的位置连边,那么图中就会产生若干个连通块,每个连通块中的节点的值都应该被构造成相同的。此时可以自然的想到把一个连通块(即,一个强连通分量)缩成一个点,然后继续接下来的操作。缩点显然可以使用 Tarjan 算法。
第二步,我们对于那些要求一定不同的点再次连边。但此时图上的点已经不是原来的点,而是原来的强连通分量,所以我们假设要连接
最后我们需要在图上把每个强连通分量赋值(因为一个强连通分量内的点的值都是相同的,所以为强连通分量赋值就相当于为这些值相同的点赋值)。由于我们要让最终的答案序列的字典序最小,也就是说我们首先要让
代码
丢了。
#include <bits/stdc++.h>
using namespace std;
const int N = 2010, M = N * N;
int n, m, cnt;
array<int, 3> p[N];
int id[N], f[N];
struct Gragh {
int h[N], e[M], ne[M], idx;
Gragh() {
memset(h, -1, sizeof h);
}
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
e[idx] = a, ne[idx] = h[b], h[b] = idx ++ ;
}
int dfn[N], low[N], stk[N], top, ts;
bool st[N];
void dfs(int u) {
dfn[u] = low[u] = ++ ts;
stk[ ++ top] = u, st[u] = true;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (!dfn[v]) {
dfs(v);
low[u] = min(low[u], low[v]);
}
else if (st[v]) low[u] = min(low[u], dfn[v]);
}
if (dfn[u] == low[u]) {
int y;
++ cnt;
do {
y = stk[top -- ];
st[y] = false;
id[y] = cnt;
} while (y != u);
}
}
void Tarjan() {
for (int i = 1; i <= n; ++ i )
if (!dfn[i]) dfs(i);
}
}G1, G2;
int main() {
freopen("b.in", "r", stdin);
freopen("b.out", "w", stdout);
cin >> n >> m;
for (int i = 1; i <= m; ++ i ) {
cin >> p[i][0] >> p[i][1] >> p[i][2];
for (int j = 0; j < p[i][2]; ++ j ) G1.add(p[i][0] + j, p[i][1] + j);
}
G1.Tarjan();
for (int i = 1; i <= m; ++ i )
if (p[i][0] + p[i][2] <= n && p[i][1] + p[i][2] <= n) {
if (id[p[i][0] + p[i][2]] == id[p[i][1] + p[i][2]]) {
puts("-1");
return 0;
}
G2.add(id[p[i][0] + p[i][2]], id[p[i][1] + p[i][2]]);
}
memset(f, -1, sizeof f);
for (int u = 1; u <= n; ++ u )
if (f[id[u]] == -1) {
set<int> S;
for (int i = G2.h[id[u]]; ~i; i = G2.ne[i]) {
int v = G2.e[i];
if (~f[v]) S.insert(f[v]);
}
for (int i = 0; ; ++ i )
if (!S.count(i)) {
f[id[u]] = i;
break;
}
}
for (int i = 1; i <= n; ++ i ) cout << f[id[i]] << ' ';
return 0;
}