Processing math: 100%

题解【bzoj4653 [NOI2016] 区间】

先按照长度排个序,然后依次添加区间。什么是添加?设这个区间是[l,r],添加就是把al,al+1,al+2,...,ar都加上1,其中ai表示第i个位置被几个区间覆盖。拿走一个区间的含义就是把它们都减1。这个过程很显然可以用线段树维护。

如果在添加到一个区间 i 时,有一个点被区间覆盖了M次,那么先更新答案,再把前面的加入过的区间一直拿直到没有一个点被覆盖M次。如何判断有没有点被覆盖M次?因为是一个一个区间加的,所以只用维护一个ai的最大值,看他是否=M就行了。

什么叫再把前面的加入过的区间一直拿直到没有一个点被覆盖M

比如你一直添加区间到第5个,此时有一个点被覆盖了M次。这时你就将第一个区间拿出,如果此时依然有有一个点被覆盖了M次,那么你就拿走第二个...

这个过程就好比一个队列,可以从后面添加区间达到一个点被覆盖了M次;从前面弹出区间直到没有一个点被覆盖了M次。

差不多就是这样,还有注意一下li,ri109,开线段树是要离散化的。上代码:

#include <bits/stdc++.h>
#define INF 1000000001
using namespace std;
const int N = 500500;
int n, m, cnt, tot, ans = INF;
struct Seg {
	int l, r, len;
	bool operator < (const Seg &x) const {
		return len < x.len;
	}
}a[N];
struct KEY {
	int d, id, se;
}key[N * 2];
inline bool cmp1(KEY x, KEY y) {
	return x.d < y.d;
}
inline bool cmp2(KEY x, KEY y) {
	return x.id < y.id;
}
struct node {
	int left, right, Max, lazy;
	node *ch[2];
}pool[N * 4], *root;
inline void pushup(node *r) {
	r->Max= max(r->ch[0]->Max, r->ch[1]->Max);
}
inline void pushdown(node *r) {
	if(!r->lazy) return ;
	r->Max += r->lazy;
	if(r->ch[0]) r->ch[0]->lazy += r->lazy;
	if(r->ch[1]) r->ch[1]->lazy += r->lazy;
	r->lazy = 0; return ;
}
inline void build(node *r, int left, int right) {
	r->left = left, r->right = right;
	if(left == right) return ;
	int mid = (left + right) >> 1;
	node *lson = &pool[++cnt], *rson = &pool[++cnt];
	r->ch[0] = lson, r->ch[1] = rson;
	build(lson, left, mid), build(rson, mid + 1, right);
}
inline void change(node *r, int left, int right, int d) {
	if(r->left == left && r->right == right) {
		r->lazy += d; return ;
	}
	pushdown(r);
	if(r->ch[0]->right >= right) change(r->ch[0], left, right, d);
	else if(r->ch[1]->left <= left) change(r->ch[1], left, right, d);
	else change(r->ch[0], left, r->ch[0]->right, d), change(r->ch[1], r->ch[1]->left, right, d);
	pushdown(r->ch[0]), pushdown(r->ch[1]), pushup(r);
}
int main() {
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++) {
		scanf("%d%d", &a[i].l, &a[i].r);
		a[i].len = a[i].r - a[i].l;
		key[++tot].d = a[i].l, key[tot].id = tot;
		key[++tot].d = a[i].r, key[tot].id = tot;
	}
	sort(key + 1, key + tot + 1, cmp1);
	key[0].d = -1; key[0].se = 0;
	for(int i = 1; i <= tot; i++)
		if(key[i].d == key[i - 1].d) 
			key[i].se = key[i - 1].se;
		else key[i].se = key[i - 1].se + 1;
	sort(key + 1, key + tot + 1, cmp2);
  for(int i = 1; i <= n; i++)
    a[i].l = key[i * 2 - 1].se, a[i].r = key[i * 2].se;
  sort(a + 1, a + n + 1);
  build(root = &pool[0], 1, 2 * n + 1);
  int pos = 1;
  change(root, a[1].l, a[1].r, 1);
  if(m == 1) ans = 0;
  for(int i = 2; i <= n; i++) {
    change(root, a[i].l, a[i].r, 1);
    while(root->Max >= m) {
  		change(root, a[pos].l, a[pos].r, -1);
  		ans = min(ans, a[i].len - a[pos].len);
  		pos++;
  	} 
  }
  if(ans == INF) ans = -1;
  printf("%d\n", ans);
  return 0;
}
posted @   AcFunction  阅读(131)  评论(0编辑  收藏  举报
编辑推荐:
· 探秘 MySQL 索引底层原理,解锁数据库优化的关键密码(下)
· 大模型 Token 究竟是啥:图解大模型Token
· 35岁程序员的中年求职记:四次碰壁后的深度反思
· 继承的思维:从思维模式到架构设计的深度解析
· 如何在 .NET 中 使用 ANTLR4
阅读排行:
· 2025,回顾出走的 10 年
· 分享 3 款基于 .NET 开源且免费的远程桌面工具
· 【保姆级教程】windows 安装 docker 全流程
· 由 MCP 官方推出的 C# SDK,使 .NET 应用程序、服务和库能够快速实现与 MCP 客户端
· 基于Docker+DeepSeek+Dify :搭建企业级本地私有化知识库超详细教程
点击右上角即可分享
微信分享提示