bzoj3716/4251 [PA2014]Muzeum

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

http://www.lydsy.com/JudgeOnline/problem.php?id=4251

【题解】

非常妙的网络流转化

首先可以把警卫和宝藏看成最大权闭合子图,用最小割的那种建模方法,即一开始加进来所有宝藏的价值

然后S连宝藏,警卫连T,有覆盖关系的连inf

那么就是一个最小割,复杂度是$O(maxflow(n+m, nm)$,显然承受不了。

由于最小割和最大流等价,所以转化最大流考虑。

问题变为

那么按x从大到小排序,每次2种操作:加入一个物品;有一个警卫可以喷水给所有y小于它物品。

显然按照y从大到小喷最优,因为小的限制条件小。

用个set维护即可,注意set的时候lower_bound只能s.lower_bound(...),不能lower_bound(s.begin(), s.end(), ..)!!!

# include <set>
# 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 = 2e5 + 10;
const int mod = 1e9+7;
const ll inf = 5e18;

inline int getint() {
    int x = 0, f = 1; char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') f = 0;
        ch = getchar();
    }
    while(isdigit(ch)) {
        x = (x<<3) + (x<<1) + ch - '0';
        ch = getchar();
    }
    return f ? x : -x;
}

int n, m, W, H;
struct pa {
    ll x, y; int v;
    pa () {} 
    pa (ll x, ll y, int v) : x(x), y(y), v(v) {}
    inline friend bool operator < (pa a, pa b) {
        return a.y < b.y || (a.y == b.y && a.x < b.x);
    }
}a[N], b[N];

struct option {
    ll x, y; int v, op;
    option() {}
    option(int op, ll x, ll y, int v) : op(op), x(x), y(y), v(v) {}
    inline friend bool operator < (option a, option b) {
        return a.x < b.x || (a.x == b.x && a.op > b.op);
    }
}p[N + N]; 

set<pa> s;
set<pa>::iterator it;

int main() { 
    ll ans = 0;
    cin >> n >> m >> W >> H;
    for (int i=1; i<=n; ++i) {
        a[i].x = 1ll * H * getint(), a[i].y = 1ll * W * getint(), a[i].v = getint(); 
        p[i] = option(1, a[i].x - a[i].y, a[i].x + a[i].y, a[i].v); ans += a[i].v; 
    }
    for (int i=1; i<=m; ++i) {
        b[i].x = 1ll * H * getint(), b[i].y = 1ll * W * getint(), b[i].v = getint(); 
        p[n + i] = option(2, b[i].x - b[i].y, b[i].x + b[i].y, b[i].v);
    }
    
    
    // maxflow
    int pn = n + m;
    sort(p+1, p+pn+1); s.clear(); 
    
    for (int i=pn; i; --i) {
        if(p[i].op == 1) s.insert(pa(p[i].x, p[i].y, p[i].v)); 
        else {
            int cv = p[i].v; 
            pa r = pa(inf, p[i].y, cv), t; 
            while(cv && s.size()) {
                it = s.upper_bound(r);
                if(it == s.begin()) break;
                --it; t = *it; s.erase(it); 
                int tmp = min(t.v, cv);
                cv -= tmp, t.v -= tmp; ans -= tmp;
                if(t.v > 0) s.insert(t); 
            }
        }
    }
    
    cout << ans;

    return 0;
}
View Code

 

posted @ 2017-07-14 22:15  Galaxies  阅读(460)  评论(0编辑  收藏  举报