首页 > 其他分享 >Solution Set 2023.12.5

Solution Set 2023.12.5

时间:2023-12-05 12:12:57浏览次数:39  
标签:std typedef Set 2023.12 valueType cap flow Solution rightarrow

[AHOI2009] 最小割

首先考虑如何处理可行边,对于边 \(\left(u, v\right)\),其为可行边与同时满足下列两个条件互为充要条件:

  • \(c_f(u, v) = 0\)
  • 在 \(G_f\) 中不存在路径 \(u \rightarrow v\)

首先可以发现若存在 \(G_f\) 使得 \(c_f(u, v) > 0\),那么一定不会割这条边。

若 \(G_f\) 中存在路径 \(u \rightarrow v\),那么可以通过将边 \(\left(u, v\right)\) 的一小部分流量通过 \(G_f\) 中存在路径 \(u \rightarrow v\) 传递。这样之后有 \(c_f(u, v) > 0\),那么一定不会割这条边。

考虑在可行边的基础上添加什么条件才可以使得边为必须边。

可以发现,若对于可行边 \(\left(u, v\right)\),若在 \(G_f\) 上不存在路径使得 \(S \rightarrow u\),那么在 \(G\) 的任意一条路径 \(S \rightarrow u\) 上,均存在令一条可行边,因此边 \(\left(u, v\right)\) 不是必须边。

所以可行边 \(\left(u, v\right)\) 是必须边当且仅当 \(G_f\) 上存在路径 \(S \rightarrow u\) 和路径 \(v \rightarrow T\)。

可以发现因为 \(c_f(u, v) = 0\),所以有 \(c_f(v, u) > 0\),即边 \(\left(v, u\right) \in G_f\),所以在 \(G_f\) 上存在路径 \(u \rightarrow v\) 等价于 \(u, v\) 在 \(G_f\) 上位于同一个强连通分量中。同理 \(G_f\) 上存在路径 \(S \rightarrow u\) 和路径 \(v \rightarrow T\) 等价于 \(u\) 和 \(S\) 在同一个强连通分量中且 \(v\) 和 \(T\) 在同一个强连通分量中。

Code
#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<bool> bitset;
typedef std::tuple<valueType, valueType, valueType> ValueTuple;
typedef std::vector<ValueTuple> TupleVector;

class Dinic {
private:
    struct Edge {
    public:
        typedef std::vector<Edge> container;
        typedef container::iterator iterator;

        valueType to;
        valueType cap;
        valueType flow;
        iterator pair;

        Edge() : to(-1), cap(-1), flow(-1), pair(){};

        Edge(valueType to, valueType cap, iterator pair = iterator()) : to(to), cap(cap), flow(0), pair(pair){};

        bool full() const {
            return flow == cap;
        }
    };

    typedef std::vector<ValueVector> Graph;
    typedef std::vector<ValueVector::iterator> IterVector;

    valueType N, M;
    Edge::container edges;
    Graph G;
    ValueVector depth;
    IterVector start;
    ValueVector belong;
    bitset inStack;
    ValueVector dfn, low;
    std::stack<valueType> stack;
    bool Initialized;

public:
    explicit Dinic(valueType N, valueType M) : N(N), M(M), edges((M << 1) + 10), G(N + 1), depth(N + 1, 0), start(N + 1), belong(N + 1, 0), inStack(N + 1, false), dfn(N + 1, 0), low(N + 1, 0), Initialized(false){};

    void addEdge(valueType from, valueType to, valueType cap, valueType id) {
        if (__builtin_expect(Initialized, false))
            throw std::runtime_error("Dinic: addEdge after init");

        edges[id << 1] = Edge(to, cap, std::next(edges.begin(), id << 1 | 1));
        edges[id << 1 | 1] = Edge(from, 0, std::next(edges.begin(), id << 1));
        G[from].emplace_back(id << 1);
        G[to].emplace_back(id << 1 | 1);
    }

    void init() {
        if (__builtin_expect(Initialized, false))
            throw std::runtime_error("Dinic: init twice");

        Initialized = true;

        std::fill(depth.begin(), depth.end(), 0);

        for (valueType i = 1; i <= N; ++i)
            start[i] = G[i].begin();
    }

    void reset() {
        if (__builtin_expect(!Initialized, false))
            throw std::runtime_error("Dinic: reset before init");

        for (valueType i = 1; i <= N; ++i)
            for (auto &iter : G[i])
                edges[iter].flow = 0;

        std::fill(depth.begin(), depth.end(), 0);

        Initialized = false;
    }

    valueType maxFlow(valueType S, valueType T) {
        if (__builtin_expect(!Initialized, false))
            throw std::runtime_error("Dinic: maxFlow before init");

        valueType result = 0;

        while (bfs(S, T)) {
            IterVector begin = start;

            result += dfs(S, T, std::numeric_limits<valueType>::max(), begin);
        }

        for (valueType i = 1; i <= N; ++i)
            if (!dfn[i])
                tarjan(i);

        return result;
    }

    valueType scc(valueType n) const {
        return belong[n];
    }

    bool full(valueType m) const {
        return edges[m].full();
    }

private:
    bool bfs(valueType S, valueType T) {
        std::fill(depth.begin(), depth.end(), 0);

        std::queue<valueType> Q;

        Q.push(S);
        depth[S] = 1;

        while (!Q.empty()) {
            valueType const u = Q.front();

            Q.pop();

            for (auto const &iter : G[u]) {
                auto const &e = edges[iter];
                if ((e.cap > e.flow) && (!depth[e.to])) {
                    depth[e.to] = depth[u] + 1;
                    Q.push(e.to);
                }
            }
        }

        return depth[T] > 0;
    }

    valueType dfs(valueType u, valueType T, valueType flow, IterVector &Begin) {
        if (u == T || flow == 0)
            return flow;

        valueType result = 0;

        for (auto &iter = Begin[u]; iter != G[u].end(); ++iter) {
            auto e = std::next(edges.begin(), *iter);
            if (e->cap > e->flow && depth[e->to] == depth[u] + 1) {
                valueType const f = dfs(e->to, T, std::min(flow - result, e->cap - e->flow), Begin);

                e->flow += f;
                e->pair->flow -= f;

                result += f;

                if (result == flow)
                    return flow;
            }
        }

        return result;
    }

    void tarjan(valueType x) {
        static valueType dfsCount = 0, sccCount = 0;

        inStack[x] = true;
        low[x] = dfn[x] = ++dfsCount;
        stack.push(x);

        for (auto const &iter : G[x]) {
            auto e = std::next(edges.begin(), iter);

            if (e->full())
                continue;

            if (!dfn[e->to]) {
                tarjan(e->to);

                low[x] = std::min(low[x], low[e->to]);
            } else if (inStack[e->to]) {
                low[x] = std::min(low[x], dfn[e->to]);
            }
        }

        if (dfn[x] == low[x]) {
            ++sccCount;

            valueType y;

            do {
                y = stack.top();

                stack.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 N, M, S, T;

    std::cin >> N >> M >> S >> T;

    Dinic dinic(N, M);

    TupleVector G;

    G.reserve(M);

    for (valueType i = 1; i <= M; ++i) {
        valueType u, v, w;

        std::cin >> u >> v >> w;

        G.emplace_back(u, v, w);

        dinic.addEdge(u, v, w, i);
    }

    dinic.init();

    dinic.maxFlow(S, T);

    for (valueType i = 0; i < M; ++i) {
        valueType const id = i + 1;

        auto const &[u, v, w] = G[i];

        bool A = dinic.full(id << 1) && dinic.scc(u) != dinic.scc(v);

        bool B = A && dinic.scc(S) == dinic.scc(u) && dinic.scc(T) == dinic.scc(v);

        std::cout << A << ' ' << B << '\n';
    }

    std::cout << std::flush;

    return 0;
}

标签:std,typedef,Set,2023.12,valueType,cap,flow,Solution,rightarrow
From: https://www.cnblogs.com/User-Unauthorized/p/2023-12-5.html

相关文章

  • 易基因:ChIP-seq等揭示SETD2介导H3K36me3调控结直肠癌进展的表观遗传机制|CTM研究
    大家好,这里是专注表观组学十余年,领跑多组学科研服务的易基因。结直肠癌(Colorectalcancer,CRC)是一种复杂的多阶段疾病,由基因突变和表观遗传改变相互作用引起。组蛋白H3K36三甲基转移酶SET结构域2(SETD2)是一种表观遗传信号分子,在结直肠癌中突变率为5%。SETD2在氧化偶氮甲烷......
  • setImmediate是什么,和setTimeout有何区别?
    setImmediate是一个用于在Node.js中执行异步操作的函数。它类似于setTimeout,但是会在当前事件循环的末尾立即执行回调函数,而不是等待一定的延迟时间。使用setImmediate可以将回调函数放置在当前事件循环的队列末尾,以确保它在下一个事件循环开始时尽快执行,而不会阻塞其他任......
  • [ARC141D] Non-divisible Set 题解
    题目链接点击打开链接题目解法很思维的题,需要用好所有的特殊性质暴力的做法是建出图,然后求包含点\(i\)的最长反链,但这明显过不了上面的做法没用到\(a_i<2m\)的性质如何用?把\(a_i\)拆分成\(q\times2^k\;(k\)为奇数\()\)的形式,那么对于同一个\(q\),只能在其中选一个......
  • 在WPF应用中使用GongSolutions.WPF.DragDrop实现列表集合控件的拖动处理
    WPF应用中,控件本身也可以通过实现事件代码实现拖动的处理,不过如果我们使用GongSolutions.WPF.DragDrop来处理,事情会变得更加简单轻松,它支持很多控件的拖动处理,如ListBox,ListView,TreeView,DataGrid等源自ItemsControl的控件,本篇随笔介绍在工作流模块中拖动TreeView和DataGrid......
  • uva12096集合栈计算机 The SetStack Computer
    洛谷链接集合栈计算机TheSetStackComputer-洛谷|计算机科学教育新生态(luogu.com.cn)一道典型的以栈为背景的数据结构题。题目简单但是程序却并不简单(个人观点)。普及组的难度有点低了感觉。个人认为这道题目可以帮助自己熟悉或者说更好的掌握STL的使用以及妙用。难点:1......
  • 云原生周刊:K8s 的 YAML 技巧 | 2023.12.4
    开源项目推荐HelmfileHelmfile是用于部署HelmChart的声明性规范。其功能有:保留图表值文件的目录并维护版本控制中的更改。将CI/CD应用于配置更改。定期同步以避免环境偏差。Docketeer一款Docker和Kubernetes开发人员工具,用于管理容器并可视化集群和容器指标。......
  • 2023.12.4学习笔记(stm32跑马灯实验——库函数)
     STM32f4有七组引脚(GPIOx),每组引脚有16个IO口,每组由十个寄存器控制。   查找STM32引脚的功能,可以在STM32F04ZGT6文件50页左右查询,此文件所在的位置为硬件资料、芯片资料文件夹里。跑马灯实验思路步骤:1:使能时钟,调用函数RCC_AHB1PeriphClockCmd();       ......
  • E - Set Meal
    E-SetMealhttps://atcoder.jp/contests/abc331/tasks/abc331_e 思路定义vector<int>v[100005];对于cd对进行group操作,得到每个aidish对应不可能的bjdish的cost值的集合 对bdishcost数组进行排序,小的在前,大的在后,对于每一个adish,使用v寻找第一个排除......
  • 2023.12.4——每日总结
    学习所花时间(包括上课):9h代码量(行):0行博客量(篇):1篇今天,上午学习,下午学习;我了解到的知识点:1.jfinal明日计划:学习......
  • 2023.12.4 近期练习
    CF1845E这种\(01\)串的描述方式一般是提出\(1\)的位置去讨论,设原串\(1\)出现位置是\(p_1,...,p_m\).考虑最后生成的串的性质,描述其\(1\)的位置,\(q_1,...q_m\)。那么至少移动步数为\(\sum|p_i-q_i|\),因为\(1\)的位置是相对不变的。考虑一个一个\(1\)往里填,设\(......