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;
}
···