题解 [NOI2016] 区间


题意

题目链接:传送门

题面比较简洁了。

碎碎念

开学前一天颓着颓着就看到这道题了

一开始想了一个假的做法:用一颗线段树维护 \([L,R]\) 的最小花费和最大权值,大概写了
\(30min\)之后发现没办法维护最大最小区间长........

然后 看了一眼题解看到了尺取法这三个字,又看了看标签里有排序,然后就没有然后了———

Solution

首先注意到一个性质:增加一个区间不会使答案更优,去掉一个区间不会使答案变差

进而注意到对于一个区间的集合 \(S\),令\(min(S)=a,max(S)=b\),则长度在\([a,b]\)中的区间对答案没有影响,也就是说它们是可有可无的。

于是我们得出一个结论,最优解的所有区间长度必然可以连续

按区间长度升序将所有区间排序,然后双指针扫扫一遍,右指针向前扫,不断更新区间最大值,当这个最大值(也就是区间内一个点被覆盖最多次数)大于等于\(m\)时,左指针向前走直到区间最大又小于\(m\)

显然区间最值可以用线段树维护,总的复杂度\(O(nlogn)\)


#include
#define rep(a,b,c) for (register int a=b;a<=c;a++)
#define per(a,b,c) for (register int a=b;a>=c;a--)
using namespace std;
typedef long long ll;
template  inline void read(T &x){
	ll f = 1;x = 0;char ch = getchar();
	while (!isdigit(ch)){if (ch == '-')f = -1;ch = getchar();}
	while (isdigit(ch)){x = (x << 1)+(x << 3)+(ch ^ 48);ch = getchar();}
	x *= f;
}

const int MAXN=500100; 

int n,m;

int b[MAXN*2],cnt,tot;

struct Section{
	int x,y,len;
	bool operator < (const Section &X) const
	{
		return len==X.len?x>1;
		build(pos<<1,L,mid);
		build(pos<<1|1,mid+1,R); 
	}
	
	inline void push_up(int pos)
	{
		maxv(pos)=max(maxv(pos<<1),maxv(pos<<1|1));
	}
	
	inline void push_down(int pos)
	{
		maxv(pos<<1)+=tag(pos),maxv(pos<<1|1)+=tag(pos);
		tag(pos<<1)+=tag(pos),tag(pos<<1|1)+=tag(pos);
		tag(pos)=0;
	}
	
	inline void modify(int pos,int L,int R,int val)
	{
		if(l(pos)>=L&&r(pos)<=R) 
		{
			maxv(pos)+=val;
			tag(pos)+=val;
			return;
		}
		if(l(pos)==r(pos))return;
		if(tag(pos))push_down(pos);
		int mid=l(pos)+r(pos)>>1;
		if(L<=mid)modify(pos<<1,L,R,val);		
		if(R>mid)modify(pos<<1|1,L,R,val);
		push_up(pos);
	} 
		
}T;

inline void init()
{
	scanf("%d%d",&n,&m);
	
	rep(i,1,n)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
		b[++tot]=a[i].x,b[++tot]=a[i].y;
		a[i].len=a[i].y-a[i].x;
	}
	sort(a+1,a+n+1);
	sort(b+1,b+tot+1);
	cnt=unique(b+1,b+tot+1)-b-1;
	 
}

inline void solve()
{
	T.build(1,1,cnt);
	int lpos,rpos;
	lpos=rpos=1;
	
	int ans=1e9; 
	while(lpos<=rpos&&rpos<=n)
	{
	
		int L=lower_bound(b+1,b+cnt+1,a[rpos].x)-b;
		int R=lower_bound(b+1,b+cnt+1,a[rpos].y)-b;	
		T.modify(1,L,R,1);
		
		while(T.maxv(1)>=m&&lpos