【NOI2016】区间

这道题作为NOI的题目还算是比较水的(虽然是第一题)
这道题是区间操作,不难看出可以用线段树

【思路分析】

由于数据很大,我们先进行离散化,然后按区间长度排序并建一棵空树(维护当前区间重合部分最大值)
根据该线段树维护的结果 ,我们可以知道t[1].sum记录的是当前各条线段重合的最大值,只要t[1].sum大于m就符合题目要求了
接着我们采用尺取法,就是搞两个指针,一部分时间复杂度可以降到 O(n)并把总体时间复杂度从O(n^2) 降到了O(nlogn)
在此基础上,我们来求最小花费,我们先将排序好的线段一段一段丢到线段树里,当t[i].sum>=m时,我们将从头开始一段一段删掉,直到不满足条件
在此操作同时,我们维护ans最小值
具体见代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define M 5000005
using namespace std;
inline int read(){
	char chr = getchar();	int f = 1,ans = 0;
	while(!isdigit(chr)) {if(chr == '-') f = -1;chr = getchar();}
	while(isdigit(chr))  {ans = ans * 10;ans += chr - '0';chr = getchar();}
	return ans* f ;
}
void write(int x){
	if(x < 0) putchar('-'),x=-x;
	if(x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
int n,m,c[M<<2],tot=0;
struct segment{int l,r,len;}a[M<<2]; //输入信息
struct node{int l,r,sum,lazy;int mid(){return l + r >> 1;} }t[M<<2];//线段树信息
bool cmp(const segment &a,const segment &b){return a.len<b.len;	}//排序
void push_down(int i){//信息下传
	if(t[i].lazy){
		t[i << 1].lazy += t[i].lazy;
		t[i << 1 | 1].lazy += t[i].lazy;
		t[i << 1].sum += t[i].lazy;
		t[i << 1 | 1].sum += t[i].lazy;
		t[i].lazy = 0;
	}
}
void push_up(int i){//信息上传
	t[i].sum = max(t[i << 1].sum,t[i << 1 | 1].sum);
}
void build(int i,int l,int r){
	t[i].l = l, t[i].r = r;
	if(l == r)	return;
	int m = t[i].mid();
	build(i << 1,l,m);
	build(i << 1 | 1,m+1,r);
}//建树
void updata(int i,int l,int r, int v){
	if(l <= t[i].l && t[i].r <= r){	t[i].lazy += v;	t[i].sum += v;	return;	}
	int m = t[i].mid();
	push_down(i);
	if(l <= m) updata(i << 1, l, r, v);
	if(r > m)  updata(i << 1 | 1, l, r, v);
	push_up(i);
}//节点更新
int main(){	
	n = read();
	m = read();
	for(int i = 1;i <= n;i++)
		a[i].l = read(),a[i].r = read(),a[i].len = a[i].r-a[i].l,c[++tot] = a[i].l,c[++tot] = a[i].r,c[++tot] = a[i].r + 1;
	sort(a + 1,a + n + 1,cmp);	sort(c + 1,c + tot + 1);	tot=unique(c + 1,c + tot + 1) - c - 1;//去重 
	int minl = 0x3f3f3f3f,maxr = -0x3f3f3f3f;
	for(int i = 1;i <=n ;i++)
		a[i].l = lower_bound(c + 1,c + tot + 1 ,a[i].l) -c,minl = min(minl,a[i].l),
		a[i].r = lower_bound(c + 1,c + tot+ 1 ,a[i].r) -c,maxr = max(maxr,a[i].r);
		//阶段1、读入、排序处理、离散化	
	int l = 1,ans = 0x3f3f3f3f;
	build(1,minl,maxr);
	for(int i = 1 ;i <= n;i++){
        updata(1, a[i].l, a[i].r, 1);
        while(t[1].sum >= m){
            ans=min(a[i].len - a[l].len,ans);
            updata(1, a[l].l, a[l].r, -1);        
            l++;
        }
    }//阶段2 尺取法求出最小花费
    if(ans == 0x3f3f3f3f) write(-1);
    else	write(ans);//输出
	return 0;
}
posted @ 2018-08-22 17:34  zheng_liwen  阅读(406)  评论(0编辑  收藏  举报
/*去广告*/