POJ1201 Intervals 差分约束(贪心也可)

题面

给定 n 个区间 [ai,bi]和 n 个整数 ci。

你需要构造一个整数集合 Z,使得∀i∈[1,n],Z 中满足ai≤x≤bi的整数 x 不少于 ci 个。

求这样的整数集合 Z 最少包含多少个数。

输入格式

第一行包含整数 n。

接下来n行,每行包含三个整数ai,bi,ci。

输出格式

输出一个整数表示结果。

数据范围

1≤n≤50000,
0≤ai,bi≤50000,
1≤ci≤bi−ai+1

输入样例:

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

输出样例:

6

题解

差分约束

一堆不等式, 明显是差分约束

设 s[i], 表示 0~i 区间选择了 s[i] 个数

则 s[b] - s[a - 1] >= c

只是这样的话, 不能将 -1(a >= 0, a - 1 >= -1)~5e4 每个节点连接起来

我们发现 s[i] - s[i - 1] >= 0, s[i - 1] - s[i] >= -1

这样就将所有节点全部连接起来, 由于解的存在, 无负环,

对于差分约束, 要么把所有点扔进队列, 要么选择一个初始节点

对于这道题要么把, 0~50000全扔进去, 要么从 -1, s[-1] ≡ 0

由于越界, 我们将 -1 由 5e4 + 1代替, 或者整体将区间右移, 变为 0~50001

const int N = 5e4 + 5;
const double eps = 1e-6;

int n, m, _, k;
int h[N], ne[N << 2], to[N << 2], co[N << 2], tot;
int a[N], b[N], c[N], dis[N];
bool v[N];

void add(int u, int v, int c) {
    ne[++tot] = h[u]; co[h[u] = tot] = c; to[tot] = v;
}

void spfa(int s) {
    queue<int> q;
    memset(dis, -1, sizeof dis);
    q.push(s); dis[s] = 0;
    while (!q.empty()) {
        int x = q.front(); q.pop(); v[x] = 0;
        for (int i = h[x]; i; i = ne[i]) {
            int y = to[i];
            if (dis[y] >= dis[x] + co[i]) continue;
            dis[y] = dis[x] + co[i];
            if (!v[y]) q.push(y), v[y] = 1;
        }
    }
}

int main() {
    sc(n);
    rep(i, 1, 5e4) add(i - 1, i, 0), add(i, i - 1, -1);
    add(5e4 + 1, 0, 0); add(0, 5e4 + 1, -1);
    rep(i, 1, n) {
        sc(a[i]), sc(b[i]), sc(c[i]); --a[i];
        if (a[i] == -1) a[i] = 5e4 + 1;
        add(a[i], b[i], c[i]);
    }
    spfa(5e4 + 1);
    pr(dis[50000]);
    return 0;
}

贪心

将b按照升序排列, 尽量将数字靠近 b 放置, 加上树状数组,并查集优化, 即可

const int N = 5e4 + 5;
const double eps = 1e-6;

int n, m, _, k;
int c[N], f[N];
pair<PII, int> p[N];

void add(int x, int k) {
    for (; x <= 5e4; x += -x & x) c[x] += k;
}

int ask(int x) {
    int ans = 0;
    for (; x; x -= -x & x) ans += c[x];
    return ans;
}

int find(int x) {
    if (x == f[x]) return x;
    return f[x] = find(f[x]);
}

int main() {
    sc(n);
    rep(i, 1, n) sc(p[i].fi.se), sc(p[i].fi.fi), sc(p[i].se);
    rep(i, 1, 5e4 + 1) f[i] = i;
    sort(p + 1, p + 1 + n);
    rep(i, 1, n) {
        int x = p[i].fi.se + 1, y = p[i].fi.fi + 1, cnt = p[i].se;
        cnt -= ask(y) - ask(x - 1);
        if (cnt <= 0) continue;
        for (int j = find(y); cnt; j = f[j])
            --cnt, add(j, 1), f[j] = find(j - 1), ++m;
    }
    pr(m);
    return 0;
}
原文地址:https://www.cnblogs.com/2aptx4869/p/13616148.html