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;
}
posted @ 2024-01-13 08:58  User-Unauthorized  阅读(13)  评论(0编辑  收藏  举报