CF1555E Boring Segments

题目传送


这题比赛的时候想出来了,挺高兴的。


首先我们把区间按花费排序,然后用一个双指针扫描花费的最大值和最小值,那么在这之间的区间都可以选,而且随着最大值的增加,其最小值的指针必然是单调不减的,因此我们只要用一个数据结构,支持区间修改和查询是否完全被覆盖就行了。

那必然是线段树了,区间修改+查询最小值,如果大于\(0\),说明整个区间都被覆盖了。


这题还有一点,就在于不同区间必须相交,而不是刚好满足\(R_i = L_j-1\)。解决方法有两个,一是区间取左闭右开,二是区间长度乘以二,即\([2L,2R]\),我的代码里采用的是第一个。

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<queue>
#include<assert.h>
#include<ctime>
using namespace std;
#define enter puts("") 
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
#define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt)
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxw = 1e6 + 6;
//const int maxn = ;
In ll read()
{
	ll ans = 0;
	char ch = getchar(), las = ' ';
	while(!isdigit(ch)) las = ch, ch = getchar();
	while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
	if(las == '-') ans = -ans;
	return ans;
}
In void write(ll x)
{
	if(x < 0) x = -x, putchar('-');
	if(x >= 10) write(x / 10);
	putchar(x % 10 + '0');
}
In void MYFILE()
{
#ifndef mrclr
	freopen(".in", "r", stdin);
	freopen(".out", "w", stdout);
#endif
}

int n, m;
struct Node
{
	int L, R;
};
vector<Node> v[maxw];

int l[maxw << 2], r[maxw << 2], Min[maxw << 2], lzy[maxw << 2];
In void build(int L, int R, int now)
{
	l[now] = L, r[now] = R;
	if(L == R) return;
	int mid = (L + R) >> 1;
	build(L, mid, now << 1), build(mid + 1, R, now << 1 | 1);
}
In void pushdown(int now)
{
	if(lzy[now])
	{
		lzy[now << 1] += lzy[now];
		Min[now << 1] += lzy[now];
		lzy[now << 1 | 1] += lzy[now];
		Min[now << 1 | 1] += lzy[now];
		lzy[now] = 0;
	}
}
In void update(int L, int R, int now, int d)
{
	if(l[now] == L && r[now] == R)
	{
		lzy[now] += d;
		Min[now] += d;
		return;
	}
	pushdown(now);
	int mid = (l[now] + r[now]) >> 1;
	if(R <= mid) update(L, R, now << 1, d);
	else if(L > mid) update(L, R, now << 1 | 1, d);
	else update(L, mid, now << 1, d), update(mid + 1, R, now << 1 | 1, d);
	Min[now] = min(Min[now << 1], Min[now << 1 | 1]);
}

int main()
{
//	MYFILE();
	n = read(), m = read();
	build(1, m - 1, 1);
	int MIN = INF, MAX = 0;
	for(int i = 1; i <= n; ++i)
	{
		int L = read(), R = read() - 1, w = read();
		v[w].push_back((Node){L, R});
		MIN = min(MIN, w);
		MAX = max(MAX, w);
	}
	int ans = INF;
	for(int i = MIN, j = MIN; i <= MAX; ++i)
	{
		if(v[i].size() == 0) continue;
		for(auto x : v[i])
		{
			int L = x.L, R = x.R;
			update(L, R, 1, 1);
		}
		while(j <= i)
		{
			if(v[j].size() == 0) {j++; continue;}
			for(auto x : v[j])
			{
				int L = x.L, R = x.R;
				update(L, R, 1, -1);
			}
			if(Min[1] == 0)
			{
				for(auto x : v[j])
				{
					int L = x.L, R = x.R;
					update(L, R, 1, 1);
				}
				break;
			}
			j++;
		}
		if(Min[1] > 0) ans = min(ans, i - j);
	}
	write(ans), enter;
	return 0;
}
···
posted @ 2021-08-01 15:02  mrclr  阅读(37)  评论(0编辑  收藏  举报