zoukankan      html  css  js  c++  java
  • bzoj3218 a + b Problem

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3218

    【题解】

    按照最小割建模,S->x连流量为white的边,x->T连流量为black的边,割掉S->x表示取黑色,割掉x->T表示取白色,一开始加上所有贡献。

    考虑奇怪的格子,一定是对于点对$(x,y)$,$x$选了黑,$y$选了白,且$y$满足条件,才会扣除$p_i$的贡献。

    暴力的想法,枚举每一对$(x,y)$关系,连边y->x,流量$p_i$。

    我们发现上面的做法有些问题,就是如果$x$是奇怪的点,且和很多白点有关系,其实会被算了很多次。

    这个问题好办,我们把每个点$x$多建一个$x'$,从$i'$向$x$连边,流量为$p_i$。

    从$j$向$i'$连边,流量为$+infty$,表示这条边不能被割。

    我们建完图,发现,卡空间。。。

    那怎么办啊?

    发现奇怪的点的关系其实是一个二维限制,可以用主席树来求出,可是求出没有什么用,边还是很多,考虑把这棵主席树全部放到建的网络流图里。

    主席树的$root_i$的区间$[l,r]$表示$a_j$在$[l,r]$内,且$j < i$的点。

    那么每次我们主席树只会新加一条链,我们把这条链自下而上连边,主席树上的边流量均为$+infty$,表示不能割掉

    那么对于每个底层区间$[p, p]$,如果有$a_j$在$p$中,连边j->这个区间的id。

    当然这样可能每个底层区间有一坨,那么就从主席树的$rt_{i-1}$的这个地方向$rt_i$的这个地方连边即可。

    每次加入点前,先查询区间$[l_i,r_i]$,把区间$[l_i,r_i]$的$O(logn)$个代表节点拉出来,跟$i'$连边。

    这样边数就在n*log级别,可以承受。

    空间开的时候稍微注意点即可。

    # include <queue>
    # include <vector>
    # include <stdio.h>
    # include <string.h>
    # include <iostream>
    # include <algorithm>
    // # include <bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    typedef long double ld;
    typedef unsigned long long ull;
    const int N = 5e3 + 10, M = 1.5e6 + 10;
    const int mod = 1e9+7, inf = 1e9;
    const int Ms = 3e6 + 5;
    
    int n;
    vector<int> ps;
    struct pa {
        int a, b, w, l, r, p;
        pa() {}
        pa(int a, int b, int w, int l, int r, int p) : a(a), b(b), w(w), l(l), r(r), p(p) {}
    }p[N];
    
    int idx = 0, S, T;
    int head[M], nxt[M], to[M], tot = 1, flow[M];
    inline void add(int u, int v, int fl) {
        ++tot; nxt[tot] = head[u]; head[u] = tot; to[tot] = v; flow[tot] = fl;
    }
    inline void adde(int u, int v, int fl) {
    //    printf("%d ---> %d, flow = %d
    
    ", u, v, fl); 
        add(u, v, fl); add(v, u, 0);
    }
    
    int rt[N], id[N];
    struct CMT {
        int ch[Ms][2], id[Ms], siz;
        inline void set() {
            siz = 0;
            memset(ch, 0, sizeof ch);
            memset(id, 0, sizeof id);
        }
        inline void edt(int &x, int y, int l, int r, int d, int lk) {
            x = ++siz, id[x] = ++idx;
            ch[x][0] = ch[y][0], ch[x][1] = ch[y][1];
            if(l == r) {
                adde(lk, id[x], inf);
                if(y) adde(id[y], id[x], inf);
                return ;
            }
            int mid = l+r>>1;
            if(d <= mid) edt(ch[x][0], ch[y][0], l, mid, d, lk);
            else edt(ch[x][1], ch[y][1], mid+1, r, d, lk);
            if(ch[x][0]) adde(id[ch[x][0]], id[x], inf);
            if(ch[x][1]) adde(id[ch[x][1]], id[x], inf);
        }
        inline void link(int x, int l, int r, int L, int R, int lk) {
            if(!x) return ;
            if(L <= l && r <= R) {
                adde(id[x], lk, inf);
                return ;
            }
            int mid = l+r>>1;
            if(L <= mid) link(ch[x][0], l, mid, L, R, lk);
            if(R > mid) link(ch[x][1], mid+1, r, L, R, lk);
        }
    }t;
    
    
    namespace MF {
        queue<int> q;
        int c[M], cur[M];
        inline bool bfs() {
            while(!q.empty()) q.pop(); 
            for (int i=1; i<=idx; ++i) c[i] = -1;
            q.push(S); c[S] = 1;
            while(!q.empty()) {
                int top = q.front(); q.pop();
                for (int i=head[top]; i; i=nxt[i]) {
                    if(c[to[i]] != -1 || !flow[i]) continue;
                    c[to[i]] = c[top] + 1;
                    q.push(to[i]);
                    if(to[i] == T) return 1;    
                }
            }
            return 0;
        }
        inline int dfs(int x, int low) {
            if(x == T) return low; 
            int r = low, fl;
            for (int i=cur[x]; i; i=nxt[i]) {
                if(c[to[i]] != c[x] + 1 || !flow[i]) continue; 
                fl = dfs(to[i], min(r, flow[i]));
                flow[i] -= fl; flow[i^1] += fl; r -= fl;
                if(flow[i] > 0) cur[x] = i; 
                if(!r) return low;
            }
            if(low == r) c[x] = -1;
            return low-r;
        }
        inline int main() {
            int ret = 0;
            while(bfs()) {
                for (int i=1; i<=idx; ++i) cur[i] = head[i];
                ret += dfs(S, inf);
            }
            return ret;
        }
    }
    
    int main() {
        int sum = 0;
        scanf("%d", &n);
        S = n+n+1, T = n+n+2;
        for (int i=1; i<=n; ++i) {
            scanf("%d%d%d%d%d%d", &p[i].a, &p[i].b, &p[i].w, &p[i].l, &p[i].r, &p[i].p);
            ps.push_back(p[i].a), ps.push_back(p[i].l), ps.push_back(p[i].r);
            adde(S, i, p[i].w); adde(i, T, p[i].b);    
            adde(i+n, i, p[i].p);
            sum = sum + p[i].w + p[i].b;
        }
        sort(ps.begin(), ps.end()); ps.erase(unique(ps.begin(), ps.end()), ps.end());
        for (int i=1; i<=n; ++i) { 
            p[i].a = lower_bound(ps.begin(), ps.end(), p[i].a) - ps.begin() + 1;
            p[i].l = lower_bound(ps.begin(), ps.end(), p[i].l) - ps.begin() + 1;
            p[i].r = lower_bound(ps.begin(), ps.end(), p[i].r) - ps.begin() + 1; 
        }
        idx = n+n+2; t.set();
        for (int i=1; i<=n; ++i) {
            t.link(rt[i-1], 1, ps.size(), p[i].l, p[i].r, i+n);
            t.edt(rt[i], rt[i-1], 1, ps.size(), p[i].a, i);
        }
        cout << sum - MF::main();
        return 0;
    }
    View Code
  • 相关阅读:
    ASP.NET---创建自定义Web控件小结
    ASP.NET---使用Asp.NET开发三层架构的应用程序
    poj 1847 最短路简单题,dijkstra
    HDU 1102 最小生成树裸题,kruskal,prim
    poj 2239 二分图最大匹配,基础题(待补)
    HDU 1520 树形dp裸题
    HDU 2089 简单数位dp
    poj 3254 状压dp入门题
    HDU 1710 二叉树遍历,输入前、中序求后序
    Poj 3250 单调栈
  • 原文地址:https://www.cnblogs.com/galaxies/p/bzoj3218.html
Copyright © 2011-2022 走看看