题目
题意:给定n个线段,长度m,每个线段有有左右端点
l
i
,
r
i
l_i,r_i
li,ri和权重
w
i
w_i
wi,现要从这n个线段选出若干个出来,使得选出的选段能衔接在一起,连通1到m。两个线段可以衔接,当且仅当它们有公共相交区域。对于每个能连通1到m的线段组合,取权值的最大值和最小值,现要求找出一组线段,使得能连通1到m,且最大值和最小值的差值最小化。
参考
题解:
看了题解才悟了按权值排序的重要性。一开始思考往线段的左右端点排序去了。
我们将线段按权值从小到大排序,接着利用双指针的思想,固定l,求能连通1到m的最小的r。我们可以往线段数里边添加边,维护最小值,当线段树的根节点的最小值大于0,则说明已完全覆盖了。
注意一个点,[1,2]和[3,5]这两个线段是不能衔接的,因为它们没有公共交点。即,我们不能当前把这个题目当成区间覆盖问题。解决方式是把每个线段的右节点都减一即可,这样区间[1,2]和[3,5](实际为[1,3],[3,6])就实际是有衔接的了,注意也要把m减一。
线段树太久没写,懒惰标记都忘记加了_(:з」∠)_
#include<bits/stdc++.h>
using namespace std;
const int maxn = 300010;
const int maxm = 1000010;
#define lson (rt << 1)
#define rson (rt << 1 | 1)
int mn[maxm<<2], lazy[maxm<<2];
int n, m;
struct node {
int l, r;
int w;
}a[maxn];
void print() {
printf("a:\n");
for (int i = 0; i < n; ++i) {
printf("[%d, %d] %d\n", a[i].l, a[i].r, a[i].w);
}
}
bool cmp(const node &a, const node &b) {
return a.w < b.w;
}
void build() {
memset(mn, 0, sizeof(mn));
memset(lazy, 0, sizeof(lazy));
}
void pushup(int rt) {
mn[rt] = min(mn[lson], mn[rson]);
}
void pushdown(int rt) {
lazy[lson] += lazy[rt];
lazy[rson] += lazy[rt];
mn[lson] += lazy[rt];
mn[rson] += lazy[rt];
lazy[rt] = 0;
}
void update(int rt, int l, int r, int a, int b, int val) {
if (l >= a && r <= b) {
lazy[rt] += val;
mn[rt] += val;
return;
}
if (lazy[rt] != 0) pushdown(rt);
int m = (l + r) >> 1;
if (a <= m) update(lson, l, m, a, b, val);
if (m < b) update(rson, m + 1, r, a, b, val);
pushup(rt);
}
int main() {
scanf("%d%d", &n, &m);
--m;
for (int i = 0; i < n; ++i) {
scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].w);
--a[i].r;
}
sort(a, a + n, cmp);
// print();//
build();
int ans = maxm;
int i = 0, j = -1;
while (i < n) {
while (j + 1 < n && mn[1] < 1) {
++j;
update(1, 1, m, a[j].l, a[j].r, 1);
}
// printf("[%d,%d] %d\n", i, j, mn[1]);
if (mn[1] < 1) break;// attention for end case
ans = min(ans, a[j].w - a[i].w);//[i,j]
if (!ans) break;
int pre = a[i].w;
while (i <= j && a[i].w == pre) {
update(1, 1, m, a[i].l, a[i].r, -1);
++i;
}
}
printf("%d\n", ans);
}
/*
9 10
6 7 10
2 3 16
5 6 13
7 8 20
9 10 6
4 5 4
3 4 10
1 2 6
8 9 20
*/