【CodeForces 269D】Maximum Waterfall(扫描线)

题目链接:【CodeForces 269D】Maximum Waterfall

题目大意:高度为 m 的墙上有 n 块木板,每个模板有一个高度 h i ,左端点 l i ,右端点 r i 。墙的顶端可以视作一个高度为 m ,左端点 10 9 ,右端点 10 9 的木板,底端同理,可以视作一个高度为 0 ,左端点 10 9 ,右端点 10 9 的木板。现在要制造一个瀑布。木板 i 的水能够流向木板 j 当且仅当以下 3 个条件同时满足:

  • m a x ( l i , l j ) m i n ( r i , r j )
  • h i > h j
  • 不存在木板 k ,使得 ( i , k ) ( k , j ) 同时满足前两个条件。

如果三个条件同时满足,则木板 i 到木板 j 的最大流量为: m i n ( r i , r j ) m a x ( l i , l j ) 。瀑布是一条路径,从墙的顶端到墙的底端。瀑布的流量是瀑布中相邻两个木板流量的最小值。求最大瀑布流量。请结合样例理解。

Sample Input:
5 6
4 1 6
3 2 7
5 9 11
3 10 15
1 13 16

Sample Output:
4

avatar

首先,发现 ( i , j ) 的对数是 Θ ( n ) 的,并且只需要知道所有的 ( i , j ) ,就很容易 D P 。所以问题的关键就是找到所有的 ( i , j ) 找出来。

将每个端点放进一个 v e c t o r 中,排序后从左到右扫。如果是右端点,则删除这块木板;否则,往数据结构中添加这块木板,并找到第一块比他高的木板和第一块比他低的木板。如果第一块比他高的木板可以到达第一块比他低的木板,则他们之间的边就要被这块木板切断。如果这块木板能到达 / 两块木板,则在他和 / 两块木板连一条边。

显然可以使用 s e t 维护。时间复杂度 Θ ( n log n )

#include <cstdio>
#include <cstring>
#include <vector>
#include <set>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair<int, int> pii;
const int maxn = 100005;
int n, m, l[maxn], r[maxn], dp[maxn];
struct point {
    int hei, x, type, id;
    point() {}
    point(int a, int b, int c, int d) {
        hei = a, x = b, type = c, id = d;
    }
    bool operator<(const point &o) const{
        return x == o.x ? type == o.type ? id < o.id : type < o.type : x < o.x;
    }
};
vector<point> p;
vector<pii> g[maxn];
set<pii> s;
int value(int l0, int r0, int l1, int r1) {
    return min(r0, r1) - max(l0, l1);
}
int dfs(int u) {
    if (u == n + 1) {
        return 2e9;
    }
    if (~dp[u]) {
        return dp[u];
    }
    for (int a, b, i = 0; i < g[u].size(); i++) {
        a = g[u][i].first, b = g[u][i].second;
        dp[u] = max(dp[u], min(b, dfs(a)));
    }
    return dp[u];
}
int main() {
    scanf("%d %d", &n, &m);
    l[0] = -1e9, r[0] = 1e9;
    l[n + 1] = -1e9, r[n + 1] = 1e9;
    for (int h, i = 1; i <= n; i++) {
        scanf("%d %d %d", &h, l + i, r + i);
        p.push_back(point(h, l[i], 1, i));
        p.push_back(point(h, r[i], 0, i));
    }
    sort(p.begin(), p.end());
    s.insert(pii(m, 0)), s.insert(pii(0, n + 1));
    for (int i = 0; i < p.size(); i++) {
        if (p[i].type) {
            set<pii>::iterator it = s.insert(pii(p[i].hei, p[i].id)).first;
            int down = (--it) -> second, up = (++++it) -> second;
            if (g[up].size() && g[up].back().first == down) {
                g[up].pop_back();
//              printf("%d -x> %d\n", up, down);
            }
            if (value(l[up], r[up], l[p[i].id], r[p[i].id])) {
                g[up].push_back(pii(p[i].id, value(l[up], r[up], l[p[i].id], r[p[i].id])));
//              printf("%d --> %d\n", up, p[i].id);
            }
            if (value(l[p[i].id], r[p[i].id], l[down], r[down])) {
                g[p[i].id].push_back(pii(down, value(l[p[i].id], r[p[i].id], l[down], r[down])));
//              printf("%d --> %d\n", p[i].id, down);
            }
        } else {
            s.erase(s.find(pii(p[i].hei, p[i].id)));
        }
    }
    memset(dp, -1, sizeof(dp));
    printf("%d\n", dfs(0));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42068627/article/details/81122179