zoukankan      html  css  js  c++  java
  • bzoj4276

    线段树优化建图+费用流

    朴素的做法是每个强盗直接对每个区间的每个点连边,然后跑最大权匹配,这样有5000*5000条边,肯定过不去,那么我们用线段树优化一下,因为线段树能把一个O(n)的区间划分为O(logn)段

    然后就建一棵线段树,每个节点向两个儿子连(inf,0)的边,叶子结点连向sink,(1,0),每个强盗向对应区间节点连边,这样边数就将为了nlogn条。据说正解是贪心?

    抄了个板子

     
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 30010, inf = 0x3f3f3f3f;
    struct edge {
        int nxt, to, f, c;
    } e[N * 100];
    int n, m, k, source, sink, tot, cnt = 1, sum;
    int head[N], pree[N], prev[N], vis[N], d[N];
    inline void link(int u, int v, int f, int c)
    {
        e[++cnt].nxt = head[u];
        head[u] = cnt;
        e[cnt].f = f;
        e[cnt].to = v;
        e[cnt].c = c;
    }
    inline void insert(int u, int v, int f, int c)
    {
        link(u, v, f, c);
        link(v, u, 0, -c);
    }
    bool spfa()
    {
        memset(d, -1, sizeof(d));
        d[source] = 0;
        queue<int> q;
        q.push(source);
        while(!q.empty())
        {
            int u = q.front();
            q.pop();
            vis[u] = 0;
            for(int i = head[u]; i; i = e[i].nxt) if(e[i].f && (d[e[i].to] < d[u] + e[i].c || d[e[i].to] == -1))
            {
                pree[e[i].to] = i;
                prev[e[i].to] = u;
                d[e[i].to] = d[u] + e[i].c;
                if(vis[e[i].to] == 0)
                {
                    q.push(e[i].to);
                    vis[e[i].to] = 1;
                }
            }
        }
        return d[sink] != -1; 
    }
    inline int Edmonds_Karp()
    {
        int ans = 0;
        while(spfa())
        {
            int now = sink, delta = inf;
            while(now != source)
            {
                delta = min(delta, e[pree[now]].f);
                now = prev[now];
            }
            now = sink;
            while(now != source)
            {
                e[pree[now]].f -= delta;
                e[pree[now] ^ 1].f += delta; 
                now = prev[now];
            }
            ans += delta * d[sink];
        } 
        return ans;
    }
    void build(int l, int r, int x)
    {
        if(l == r) 
        {
            insert(x, sink, 1, 0);
            return;
        }
        int mid = (l + r) >> 1;
        build(l, mid, x << 1);
        build(mid + 1, r, x << 1 | 1);
        insert(x, x << 1, inf, 0);
        insert(x, x << 1 | 1, inf, 0);
    }
    void update(int l, int r, int x, int a, int b, int c, int pos)
    {
        if(l > b || r < a) return;
        if(l >= a && r <= b) 
        {
            insert(pos, x, 1, c);
            return;
        }
        int mid = (l + r) >> 1;
        update(l, mid, x << 1, a, b, c, pos);
        update(mid + 1, r, x << 1 | 1, a, b, c, pos);
    }
    int main()
    {
        scanf("%d", &n);
        sink = 20000 + n + 1;
        build(1, 5000, 1);
        for(int i = 1; i <= n; ++i) 
        {
            int l, r, c;
            scanf("%d%d%d", &l, &r, &c);
            insert(source, i + 20000, 1, 0);
            update(1, 5000, 1, l, r - 1, c, i + 20000); 
        }   
        printf("%d
    ", Edmonds_Karp());
        return 0;
    }
    View Code
  • 相关阅读:
    ubuntu安装软件失败
    阶乘函数 注意事项
    汇编退出
    vim比较文件
    汇编调试
    Redis
    记录一次ajax使用
    oracle11g导出dmp文件时不能导出空表,导致缺表
    将小数点后的0去掉
    redis
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7529922.html
Copyright © 2011-2022 走看看