题目大意:n个站点,有m群奶牛,第i群奶牛有mi只,要从si站点出发,直到ti站点下车。对于一群奶牛,可以不全部上车。同时在车上的奶牛数不能超过c,求最多能满足多少头奶牛的要求。
Sol:
一开始想到的是非常朴素的费用流,建模通过等式差分十分显然。不过这样会严重超时。
用两个变量now,ans分别记录当前负载,以及答案。
再维护每群奶牛目前剩下的数目num。
将奶牛群按照si从大到小排序,依次处理。
对于当前奶牛群i,我们找出还剩下的奶牛群j中tj<=si的奶牛群,并还原负载:now+=numj.
我们令当前奶牛群全部上车,不过有可能超出负载,那么我们就贪心的减小当前还剩下的ti最大的奶牛群,直到负载满足条件。在这个过程中,更新答案。
这样我们就在O(mlogm)的时间复杂度内解决了此题。
具体实现方面,分别维护大根堆和小根堆,维护ti.
Code:
#include <cstdio> #include <cstring> #include <cctype> #include <iostream> #include <algorithm> using namespace std; #define N 20010 #define M 50010 int n, m; struct Interval { int l, r, num; Interval(int _l = 0, int _r = 0, int _num = 0):l(_l),r(_r),num(_num){} void read() { scanf("%d%d%d", &l, &r, &num); } bool operator < (const Interval &B) const { return l < B.l; } }S[M]; inline bool cmp(int a, int b) {//return a < b return S[a].r < S[b].r; } struct Heap { int a[M], ch[M], top; bool d; Heap(bool _d):d(_d) { top = 0; } bool empty() { return (top == 0); } void up(const int &x, bool del) { for(int i = x; i != 1; i >>= 1) { if (del || (cmp(a[i], a[i >> 1]) ^ d)) { swap(ch[a[i]], ch[a[i >> 1]]); swap(a[i], a[i >> 1]); } else break; } } void down(const int &x) { int son; for(int i = x; (i << 1) <= top; ) { son=(((i<<1)==top)||(cmp(a[i<<1],a[(i<<1)|1])^d))?(i<<1):((i<<1)|1); if (cmp(a[son], a[i]) ^ d) { swap(ch[a[i]], ch[a[son]]); swap(a[i], a[son]); i = son; } else break; } } void insert(const int &x) { a[++top] = x; ch[x] = top; up(top, 0); } void pop() { a[1] = a[top]; ch[a[top--]] = 1; down(1); } void cutdown(const int &x) { int ins = ch[x]; up(ins, 1); pop(); } int res() { return a[1]; } }Max(1), Min(0); int main() { //freopen("tt.in", "r", stdin); int lim; scanf("%d%d%d", &m, &n, &lim); int i; for(i = 1; i <= m; ++i) S[i].read(); sort(S + 1, S + m + 1); S[0].r = -1; S[m + 1].r = 1 << 30; int now = 0, ans = 0, x; for(i = 1; i <= m; ++i) { while(!Min.empty() && S[x = Min.res()].r <= S[i].l) { Min.cutdown(x); Max.cutdown(x); now -= S[x].num; } now += S[i].num; ans += S[i].num; Min.insert(i); Max.insert(i); while(now > lim) { x = Max.res(); if (S[x].num > now - lim) { ans -= now - lim; S[x].num -= now - lim; now = lim; break; } else { Min.cutdown(x); Max.cutdown(x); ans -= S[x].num; now -= S[x].num; } } } printf("%d", ans); return 0; }