Solution Set【2024.1.13】
B. 山河入梦来
不难发现所求的其实就是该矩阵的行列式,考虑对矩阵进行高斯消元后求解。
我们考虑高斯消元的过程:从左到右枚举列,对于当前枚举的列,我们需要找到一个非零的行,使得该行的当前列的值为1,并且通过消元使得该列的其他行的值为0。
不难发现对于所有从当前列开始的连续的 \(1\) 中,取最短的一个即可,因此可以使用堆来维护连续的 \(1\),每次需要取的时候取最短的即可,对于其他的行,我们模拟高斯消元的过程即可。
Code
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/tree_policy.hpp>
typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
//typedef __gnu_pbds::priority_queue<ValuePair, std::greater<>, __gnu_pbds::pairing_heap_tag> PairQueue;
typedef std::priority_queue<ValuePair, std::vector<ValuePair>, std::greater<>> PairQueue;
typedef std::vector<PairQueue> QueueVector;
namespace IO {
constexpr valueType SIZE = (1 << 25);
char ibuf[SIZE], *pi = ibuf;
inline valueType rnt() {
valueType x = 0;
char c = *pi++;
while (!isdigit(c))
c = *pi++;
while (isdigit(c))
x = (x << 3) + (x << 1) + (c ^ 48), c = *pi++;
return x;
}
char obuf[SIZE >> 10], *po = obuf;
inline void wnt(valueType x) {
static valueType sta[35];
valueType top = 0;
do {
sta[top++] = x % 10, x /= 10;
} while (x);
while (top)
*po++ = sta[--top] + '0';
}
inline void wts(char const *s) {
while (*s)
*po++ = *s++;
*po++ = '\n';
}
}// namespace IO
template<typename T, class Operator = std::plus<>>
class TreeArray {
private:
T N;
std::vector<T> tree;
Operator op;
static T lowbit(T x) {
return x & (-x);
}
public:
TreeArray() = default;
explicit TreeArray(T n, T initValue = 0) : N(n), tree(n + 1, initValue) {}
void insert(T pos, T value) {
#ifdef _UU_DEBUG
if (pos <= 0 || pos > N)
throw std::out_of_range("TreeArray::insert() : pos out of range");
#endif
while (pos <= N) {
tree[pos] = op(tree[pos], value);
pos += lowbit(pos);
}
}
T query(T pos) {
#ifdef _UU_DEBUG
if (pos <= 0 || pos > N)
throw std::out_of_range("TreeArray::query() : pos out of range");
#endif
T result = 0;
while (pos > 0) {
result = op(result, tree[pos]);
pos -= lowbit(pos);
}
return result;
}
};
valueType GetInverseCount(valueType N, ValueVector const &P) {
valueType result = 0;
TreeArray<valueType> tree(N);
for (valueType i = 1; i <= N; i++) {
result += i - 1 - tree.query(P[i]);
tree.insert(P[i], 1);
}
return result;
}
valueType Inverse(valueType N, ValueVector const &P) {// Computes the reverse logarithm of a permutation of order N
__gnu_pbds::tree<valueType, __gnu_pbds::null_type, std::greater<>, __gnu_pbds::rb_tree_tag, __gnu_pbds::tree_order_statistics_node_update> T;
valueType result = 0;
for (valueType i = 1; i <= N; ++i) {
result += (valueType) T.order_of_key(P[i]);
T.insert(P[i]);
}
return result;
}
std::pair<bool, ValueVector> solve(valueType N, PairVector const &A) {
ValueVector P(N + 2, 0);
QueueVector Q(N + 2);
for (valueType i = 1; i <= N; ++i)
Q[A[i].first].push(ValuePair(A[i].second, i));
for (valueType i = 1; i <= N; ++i) {
if (Q[i].empty())
return std::make_pair(false, ValueVector(N + 1, 0));
auto const [r, id] = Q[i].top();
Q[i].pop();
P[id] = i;
if (!Q[i].empty() && Q[i].top().first == r)
return std::make_pair(false, ValueVector(N + 1, 0));
if (Q[r + 1].size() < Q[i].size())
std::swap(Q[r + 1], Q[i]);
while (!Q[i].empty()) {
Q[r + 1].push(Q[i].top());
Q[i].pop();
}
}
return std::make_pair(true, P);
}
void solve() {
// auto begin = std::chrono::steady_clock::now();
valueType N;
// std::cin >> N;
N = IO::rnt();
PairVector Y(N + 1);
for (valueType i = 1; i <= N; ++i) {
// std::cin >> Y[i].first >> Y[i].second;
Y[i].first = IO::rnt();
Y[i].second = IO::rnt();
}
auto const [ok, P] = solve(N, Y);
// std::cerr << "solve: " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - begin).count() << std::endl;
if (!ok) {
// std::cout << "tie" << std::endl;
IO::wts("tie");
return;
}
valueType const Inv = GetInverseCount(N, P);
// std::cerr << "solve Inverse : " << std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - begin).count() << std::endl;
// std::cout << (Inv & 1 ? "xx" : "pp") << std::endl;
IO::wts((Inv & 1 ? "xx" : "pp"));
}
int main() {
// std::ios::sync_with_stdio(false);
// std::cin.tie(nullptr);
// std::cout.tie(nullptr);
#ifndef LOCAL_STDIO
freopen("river.in", "r", stdin);
freopen("river.out", "w", stdout);
#endif
fread(IO::ibuf, 1, IO::SIZE, stdin);
valueType T;
// std::cin >> T;
T = IO::rnt();
for (valueType testcase = 0; testcase < T; ++testcase)
solve();
fwrite(IO::obuf, 1, IO::po - IO::obuf, stdout);
return 0;
}
[NOI2017] 游戏
发现除 \(x\) 外,每种地图可以使用的赛车类型数量均为 \(2\),不难转化为 2-sat 问题,具体的,对于限制 \(\left(i, h_i, j, h_j\right)\),设 \(h_i^{\prime}\) 表示第 \(i\) 场除 \(h_i\) 外可以使用的赛车类型,\(h_j^{\prime}\) 同理,那么我们可按 \(h_i\) 和 \(h_j\) 是否可以使用来处理限制:
-
若第 \(i\) 场不能使用 \(h_i\),那么该限制无需处理。
-
若第 \(j\) 场不能使用 \(h_j\),那么这也就意味着第 \(i\) 场不能使用 \(h_i\)。因此建边 \(h_i \rightarrow h_i^{\prime}\)。
-
否则意味着第 \(i\) 场可以使用 \(h_i\),且第 \(j\) 场可以使用 \(h_j\),那么建边 \(h_i \rightarrow h_j\),\(h_j^{\prime} \rightarrow h_i^{\prime}\)。
考虑如何处理 \(x\),考虑对于每个 \(x\),为其制定一种地图。不妨假设最终的赛车方案是确定的,那么可以每种赛车对应了两张可以使用的地图,因此若我们随机确定 \(x\) 的地图类型,有解的概率为 \(\dfrac{2^d}{3^d}\),因为有 \(d \le 8\),因此正确率不低于 \(3 \%\),多次随机即可通过。
Code
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("inline")
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::stack<valueType> ValueStack;
typedef std::vector<bool> bitset;
typedef std::tuple<valueType, char, valueType, char> LimitTuple;
typedef std::vector<LimitTuple> LimitVector;
typedef std::string string;
valueType N, M, size;
string S;
LimitVector Limits;
ValueMatrix G;
std::array<valueType, 100001> dfn, low, belong;
valueType sccCount = 0, dfsCount = 0;
ValueVector stack;
std::bitset<100001> inStack;
std::array<std::array<char, 2>, 256> SourceTable;
std::vector<std::array<char, 2>> Table;
void tarjan(valueType x) {
dfn[x] = low[x] = ++dfsCount;
stack.push_back(x);
inStack[x] = true;
for (auto const &to : G[x]) {
if (!dfn[to]) {
tarjan(to);
low[x] = std::min(low[x], low[to]);
} else if (inStack[to]) {
low[x] = std::min(low[x], dfn[to]);
}
}
if (dfn[x] == low[x]) {
++sccCount;
valueType y;
do {
y = stack.back();
stack.pop_back();
inStack[y] = false;
belong[y] = sccCount;
} while (y != x);
}
}
inline void Init() {
for (auto &vec : G)
vec.clear();
dfn.fill(0);
low.fill(0);
belong.fill(0);
sccCount = 0;
dfsCount = 0;
}
inline bool Check(valueType pos, char car) {
return S[pos] - car != 32;
}
inline valueType ID(valueType pos, char car) {
return Table[pos][0] == car ? 0 : 1;
}
inline char GetCar(valueType pos, valueType id) {
return Table[pos][id];
}
bool Check() {
Init();
for (auto const &limit : Limits) {
valueType x, y, LimitX, LimitY;
std::tie(x, LimitX, y, LimitY) = limit;
if (!Check(x, LimitX))
continue;
if (!Check(y, LimitY)) {
valueType const id = ID(x, LimitX);
G[x + id * N].push_back(x + (1 - id) * N);
continue;
}
valueType NotX = x + N, NotY = y + N;
if (ID(x, LimitX))
std::swap(x, NotX);
if (ID(y, LimitY))
std::swap(y, NotY);
G[x].push_back(y);
G[NotY].push_back(NotX);
}
for (valueType i = 1; i <= size; ++i) {
if (!dfn[i])
tarjan(i);
}
for (valueType i = 1; i <= N; ++i) {
if (belong[i] == belong[i + N])
return false;
}
for (valueType i = 1; i <= N; ++i) {
if (belong[i] > belong[i + N]) {
std::cout << GetCar(i, 1);
} else {
std::cout << GetCar(i, 0);
}
}
std::cout << std::endl;
return true;
}
constexpr auto TimeLimit = std::chrono::milliseconds(950);
int main() {
auto __begin = std::chrono::steady_clock::now();
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
SourceTable['a'][0] = 'B';
SourceTable['a'][1] = 'C';
SourceTable['b'][0] = 'A';
SourceTable['b'][1] = 'C';
SourceTable['c'][0] = 'A';
SourceTable['c'][1] = 'B';
valueType D;
std::cin >> N >> D;
size = 2 * N;
stack.reserve(size);
G.resize(size + 1);
for (auto &vec : G)
vec.reserve(20);
std::cin >> S;
S = '#' + S;
std::cin >> M;
Limits.resize(M);
Table.resize(N + 1);
for (valueType i = 1; i <= N; ++i) {
Table[i] = SourceTable[S[i]];
}
for (auto &[x, LimitX, y, LimitY] : Limits)
std::cin >> x >> LimitX >> y >> LimitY;
ValueVector X;
X.reserve(D);
std::mt19937 engine(std::chrono::steady_clock::now().time_since_epoch().count() ^ std::random_device()() ^ (size_t) (std::make_unique<char>().get()));
for (valueType i = 1; i <= N; ++i)
if (S[i] == 'x')
X.push_back(i);
auto CheckTime = [&]() {
auto __end = std::chrono::steady_clock::now();
return std::chrono::duration_cast<std::chrono::milliseconds>(__end - __begin) < TimeLimit;
};
for (valueType i = 0; i < D; ++i) {
S[X[i]] = 'a' + engine() % 3;
Table[X[i]] = SourceTable[S[X[i]]];
}
while (CheckTime()) {
for (valueType i = 0; i < D; ++i) {
S[X[i]] = 'a' + engine() % 3;
Table[X[i]] = SourceTable[S[X[i]]];
}
if (Check())
return 0;
}
std::cout << -1 << std::endl;
std::exit(0);
}
[PA2010] Riddle
设变量 \(s_i\) 表示第 \(i\) 个数是否是关键点,那么不难发现我们需要处理两种限制:
-
每条边至少有一个端点是关键点,其等价于对于边 \(\left(u, v\right)\) 满足 \(s_u \lor s_v\)
-
每个部分恰有一个关键点,对于某个部分 \(S\),其等价于 \(\forall i, j \in S \land i \neq j \rightarrow \lnot s_i \lnot s_j\)。这是因为若存在某种方案使得某个部分内没有关键点,那么在该部分中任选一个点作为关键点,其仍然满足限制,因此我们可以将限制放宽为至多一个关键点。
考虑使用 2-sat 求解,发现难点在于第二种限制的条件数目是 \(O\left(n^2\right)\) 的,因此我们需要对其进行优化。
不难发现第二种限制从每个节点的角度看,其实际上是对于集合内的其他全部元素均有限制,考虑将集合转化为序列,那么对于序列中的每个元素,其实际上是对于序列中的其他全部元素均有限制,即其前缀和后缀,因此使用前缀优化建图即可。
Code
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::stack<valueType> ValueStack;
typedef std::vector<bool> bitset;
valueType N, M, size;
ValueMatrix G;
ValueVector dfn, low, belong;
valueType sccCount = 0;
ValueStack S;
bitset inStack;
void tarjan(valueType x, valueType &dfsCount) {
dfn[x] = low[x] = ++dfsCount;
S.push(x);
inStack[x] = true;
for (auto const &to : G[x]) {
if (!dfn[to]) {
tarjan(to, dfsCount);
low[x] = std::min(low[x], low[to]);
} else if (inStack[to]) {
low[x] = std::min(low[x], dfn[to]);
}
}
if (dfn[x] == low[x]) {
++sccCount;
valueType y;
do {
y = S.top();
S.pop();
inStack[y] = false;
belong[y] = sccCount;
} while (y != x);
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType K;
std::cin >> N >> M >> K;
size = 4 * N;
G.resize(size + 1);
dfn.resize(size + 1);
low.resize(size + 1);
belong.resize(size + 1);
inStack.resize(size + 1);
for (valueType m = 0; m < M; ++m) {
valueType x, y;
std::cin >> x >> y;
valueType NotX = x + N, NotY = y + N;
G[NotX].push_back(y);
G[NotY].push_back(x);
}
valueType nodeCount = 2 * N;
for (valueType k = 0; k < K; ++k) {
valueType count;
std::cin >> count;
ValueVector V(count);
for (valueType i = 0; i < count; ++i)
std::cin >> V[i];
for (valueType i = 0; i < count; ++i) {
if (i > 0)
G[V[i]].push_back(nodeCount);
valueType const prev = i == 0 ? V[i] + N : nodeCount;
valueType const now = ++nodeCount;
G[now].push_back(prev);
G[now].push_back(V[i] + N);
}
std::reverse(V.begin(), V.end());
for (valueType i = 0; i < count; ++i) {
if (i > 0)
G[V[i]].push_back(nodeCount);
valueType const prev = i == 0 ? V[i] + N : nodeCount;
valueType const now = ++nodeCount;
G[now].push_back(prev);
G[now].push_back(V[i] + N);
}
}
valueType dfsCount = 0;
for (valueType i = 1; i <= size; ++i) {
if (!dfn[i])
tarjan(i, dfsCount);
}
for (valueType i = 1; i <= N; ++i) {
if (belong[i] == belong[i + N]) {
std::cout << "NIE" << std::endl;
return 0;
}
}
std::cout << "TAK" << std::endl;
}
「POI2011 R1」同谋者 Conspiracy
使用 2-sat 判断是否有解并求出一个合法解是容易的,这里不多赘述。
下面主要考虑如何求出解的数量。
考虑在已经求出的解的基础上,如何求出下一个解。不妨改变当前解下某些人的位置。可以发现,对于某一部分,其至多有一人改变位置,这是因为若存在不小于两人改变位置,那么这两人之间的关系一定不符合另一组织的限制。
因此我们可以对于每个人,考虑其是否可以改变位置。考虑在后勤组织的一人,若其可以改变位置,那么同谋者团队中至多一人与其相识,且这个人一定与其同时改变位置。定义这个人是其的限制人。那么我们可以对于每个人,求出其限制人的集合,然后对于每个人考虑其是否可以改变位置,这样就可以求出下一个解。
Code
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::stack<valueType> ValueStack;
typedef std::vector<bool> bitset;
typedef std::vector<bitset> BitMatrix;
valueType N, size;
ValueMatrix G;
ValueVector dfn, low, belong;
valueType sccCount = 0;
ValueStack S;
bitset inStack;
void tarjan(valueType x, valueType &dfsCount) {
dfn[x] = low[x] = ++dfsCount;
S.push(x);
inStack[x] = true;
for (auto const &to : G[x]) {
if (!dfn[to]) {
tarjan(to, dfsCount);
low[x] = std::min(low[x], low[to]);
} else if (inStack[to]) {
low[x] = std::min(low[x], dfn[to]);
}
}
if (dfn[x] == low[x]) {
++sccCount;
valueType y;
do {
y = S.top();
S.pop();
inStack[y] = false;
belong[y] = sccCount;
} while (y != x);
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
std::cin >> N;
size = 2 * N;
G.resize(size + 1);
dfn.resize(size + 1);
low.resize(size + 1);
belong.resize(size + 1);
inStack.resize(size + 1);
BitMatrix relation(N + 1, bitset(N + 1, false));
for (valueType i = 1; i <= N; ++i) {
valueType k;
std::cin >> k;
for (valueType j = 0; j < k; ++j) {
valueType x;
std::cin >> x;
relation[i][x] = true;
}
}
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 1; j <= N; ++j) {
if (i == j)
continue;
if (relation[i][j]) {
G[i + N].push_back(j);
} else {
G[i].push_back(j + N);
}
}
}
valueType dfsCount = 0;
for (valueType i = 1; i <= size; ++i) {
if (!dfn[i])
tarjan(i, dfsCount);
}
for (valueType i = 1; i <= N; ++i) {
if (belong[i] == belong[i + N]) {
std::cout << "0" << std::endl;
return 0;
}
}
bitset ans(N + 1, false);
valueType TrueCount = 0, FalseCount = 0;
for (valueType i = 1; i <= N; ++i) {
if (belong[i] < belong[i + N]) {
ans[i] = true;
++TrueCount;
} else {
ans[i] = false;
++FalseCount;
}
}
ValueVector pair(N + 1, 0);
for (valueType i = 1; i <= N; ++i) {
if (ans[i]) {
for (valueType j = 1; j <= N; ++j) {
if (ans[j])
continue;
if (relation[i][j]) {
if (pair[i] == 0)
pair[i] = j;
else
pair[i] = -1;
}
}
} else {
for (valueType j = 1; j <= N; ++j) {
if (!ans[j])
continue;
if (!relation[i][j]) {
if (pair[i] == 0)
pair[i] = j;
else
pair[i] = -1;
}
}
}
}
valueType count = (TrueCount > 0 && FalseCount > 0 ? 1 : 0);
for (valueType i = 1; i <= N; ++i) {
if (pair[i] == 0 && (ans[i] ? TrueCount : FalseCount) > 1)
++count;
}
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 1; j < i; ++j) {
if (ans[i] != ans[j] && (pair[i] == 0 || pair[i] == j) && (pair[j] == 0 || pair[j] == i))
++count;
}
}
std::cout << count << std::endl;
return 0;
}
CF1697F Too Many Constraints / ABC277Ex Constrained Sums
一个直觉的想法是建出 \(n \times k\) 个变量,其中依次考虑某个数是否取到某个值,但是考察限制关系发现在实际建图下限制的节点均是前后缀的形式。因此可以直接设变量 \(s_{i, j}\) 表示是否满足 \(a_i \le j\)。
进而直接按限制建图即可。
需要注意的一点是,我们需要保证 \(s_{n, k}\) 为 \(\tt{False}\),否则可能会出现元素不满足值域限制的情况。
Code of CF1697F
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::stack<valueType> ValueStack;
typedef std::vector<bool> bitset;
typedef std::vector<bitset> BitMatrix;
valueType N, M, K, size;
ValueMatrix G;
ValueVector dfn, low, belong;
valueType sccCount = 0;
ValueStack S;
bitset inStack;
void tarjan(valueType x, valueType &dfsCount) {
dfn[x] = low[x] = ++dfsCount;
S.push(x);
inStack[x] = true;
for (auto const &to : G[x]) {
if (!dfn[to]) {
tarjan(to, dfsCount);
low[x] = std::min(low[x], low[to]);
} else if (inStack[to]) {
low[x] = std::min(low[x], dfn[to]);
}
}
if (dfn[x] == low[x]) {
++sccCount;
valueType y;
do {
y = S.top();
S.pop();
inStack[y] = false;
belong[y] = sccCount;
} while (y != x);
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
valueType T;
std::cin >> T;
for (valueType testcase = 0; testcase < T; ++testcase) {
G.clear();
dfn.clear();
low.clear();
belong.clear();
sccCount = 0;
inStack.clear();
std::cin >> N >> M >> K;
size = 0;
ValueMatrix True(N + 1, ValueVector(K + 1));
ValueMatrix False(N + 1, ValueVector(K + 1));
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 1; j <= K; ++j) {
True[i][j] = ++size;
False[i][j] = ++size;
}
}
G.resize(size + 1);
dfn.resize(size + 1);
low.resize(size + 1);
belong.resize(size + 1);
inStack.resize(size + 1);
ValueVector Pair(size + 1, 0);
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 1; j <= K; ++j) {
Pair[True[i][j]] = False[i][j];
Pair[False[i][j]] = True[i][j];
}
}
auto Sure = [&](valueType x, valueType y) {// Add condition that x -> y
if (x == y || x < 1 || x > size || y < 1 || y > size)
// return;
std::abort();
G[x].push_back(y);
G[Pair[y]].push_back(Pair[x]);
};
auto Not = [&](valueType x) {// Add condition that !x
Sure(x, Pair[x]);
};
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 1; j < K; ++j)
Sure(True[i][j], True[i][j + 1]);
}
for (valueType j = 1; j <= K; ++j) {
for (valueType i = 2; i <= N; ++i)
Sure(True[i][j], True[i - 1][j]);
}
Not(False[N][K]);
for (valueType m = 0; m < M; ++m) {
valueType type;
std::cin >> type;
if (type == 1) {
valueType i, x;
std::cin >> i >> x;
if (x == 1) {
Not(True[i][x]);
} else {
Sure(True[i][x], True[i][x - 1]);
}
} else if (type == 2) {
valueType i, j, x;
std::cin >> i >> j >> x;
if (x - 1 < K) {
Not(False[i][x - 1]);
Not(False[j][x - 1]);
}
for (valueType y = 1; y <= K; ++y) {
if (1 <= x - y - 1 && x - y - 1 <= K) {
Sure(False[i][y], True[j][x - y - 1]);
Sure(False[j][y], True[i][x - y - 1]);
}
}
} else if (type == 3) {
valueType i, j, x;
std::cin >> i >> j >> x;
if (x - K > 1) {
Not(True[i][x - K - 1]);
Not(True[j][x - K - 1]);
}
for (valueType y = 1; y <= K; ++y) {
if (1 <= x - y - 1 && x - y - 1 <= K) {
Sure(True[i][y], False[j][x - y - 1]);
Sure(True[j][y], False[i][x - y - 1]);
}
}
} else {
std::abort();
}
}
valueType dfsCount = 0;
for (valueType i = 1; i <= size; ++i) {
if (!dfn[i])
tarjan(i, dfsCount);
}
bool ok = true;
for (valueType i = 1; i <= N && ok; ++i) {
for (valueType j = 1; j <= K && ok; ++j) {
if (belong[True[i][j]] == belong[False[i][j]])
ok = false;
}
}
if (!ok) {
std::cout << -1 << std::endl;
continue;
}
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 1; j <= K; ++j) {
if (belong[True[i][j]] < belong[False[i][j]]) {
std::cout << j << ' ';
break;
}
}
}
std::cout << std::endl;
}
std::cout << std::flush;
return 0;
}
Code of ABC277Ex
#include <bits/stdc++.h>
typedef int valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::stack<valueType> ValueStack;
typedef std::vector<bool> bitset;
typedef std::vector<bitset> BitMatrix;
valueType N, M, Q, size;
ValueMatrix G;
ValueVector dfn, low, belong;
valueType sccCount = 0;
ValueStack S;
bitset inStack;
void tarjan(valueType x, valueType &dfsCount) {
dfn[x] = low[x] = ++dfsCount;
S.push(x);
inStack[x] = true;
for (auto const &to : G[x]) {
if (!dfn[to]) {
tarjan(to, dfsCount);
low[x] = std::min(low[x], low[to]);
} else if (inStack[to]) {
low[x] = std::min(low[x], dfn[to]);
}
}
if (dfn[x] == low[x]) {
++sccCount;
valueType y;
do {
y = S.top();
S.pop();
inStack[y] = false;
belong[y] = sccCount;
} while (y != x);
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
std::cin >> N >> M >> Q;
size = 0;
ValueMatrix True(N + 1, ValueVector(M + 1));
ValueMatrix False(N + 1, ValueVector(M + 1));
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 0; j <= M; ++j) {
True[i][j] = ++size;
False[i][j] = ++size;
}
}
G.resize(size + 1);
dfn.resize(size + 1);
low.resize(size + 1);
belong.resize(size + 1);
inStack.resize(size + 1);
ValueVector Pair(size + 1, 0);
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 0; j <= M; ++j) {
Pair[True[i][j]] = False[i][j];
Pair[False[i][j]] = True[i][j];
}
}
auto Sure = [&](valueType x, valueType y) {// Add condition that x -> y
if (x == y || x < 0 || x > size || y < 0 || y > size)
std::abort();
G[x].push_back(y);
G[Pair[y]].push_back(Pair[x]);
};
auto Not = [&](valueType x) {// Add condition that !x
Sure(x, Pair[x]);
};
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 0; j < M; ++j)
Sure(True[i][j], True[i][j + 1]);
Not(False[i][M]);
}
for (valueType q = 0; q < Q; ++q) {
valueType A, B, L, R;
std::cin >> A >> B >> L >> R;
if (A == B) {
L = L == 0 ? -1 : (L - 1) / 2;
R = R / 2;
if (L != -1)
Not(True[A][L]);
Not(False[A][R]);
continue;
}
if (R < M) {
Not(False[A][R]);
Not(False[B][R]);
}
for (valueType y = 0; y <= M; ++y) {
if (0 <= R - y - 1 && R - y - 1 <= M) {
Sure(False[A][y], True[B][R - y - 1]);
Sure(False[B][y], True[A][R - y - 1]);
}
}
if (L > M) {
Not(True[A][L - M - 1]);
Not(True[B][L - M - 1]);
}
for (valueType y = 0; y <= M; ++y) {
if (0 <= L - y - 1 && L - y - 1 <= M) {
Sure(True[A][y], False[B][L - y - 1]);
Sure(True[B][y], False[A][L - y - 1]);
}
}
}
valueType dfsCount = 0;
for (valueType i = 1; i <= size; ++i) {
if (!dfn[i])
tarjan(i, dfsCount);
}
bool ok = true;
for (valueType i = 1; i <= N && ok; ++i) {
for (valueType j = 0; j <= M && ok; ++j) {
if (belong[True[i][j]] == belong[False[i][j]])
ok = false;
}
}
if (!ok) {
std::cout << -1 << std::endl;
return 0;
}
for (valueType i = 1; i <= N; ++i) {
for (valueType j = 0; j <= M; ++j) {
if (belong[True[i][j]] < belong[False[i][j]]) {
std::cout << j << ' ';
break;
}
}
}
std::cout << std::endl;
return 0;
}