[BZOJ4082][Wf2014]Surveillance[倍增]

题意

给你一个长度为 \(len\) 的环,以及 \(n\) 个区间,要你选择尽量少的区间,使得它们完全覆盖整个环。问最少要多少个区间。

\(len,n\leq 10^6\) .

分析

  • 考虑普通的区间覆盖的贪心做法,这里只需要倍增一下。

  • 如果区间 \(r< l\)\(r\) 设置成 \(r+len\)

  • 每个解都一定存在一个区间满足其标号最小,且可以通过后面的区间跳回自己的右边,只需要以这类区间开头即可。

  • 总时间复杂度为 \(O(nlogn)\) .

处理区间覆盖的技巧:记录**后缀最小值 **\(mn\),如果\(mn\leq l+1\) 就让指针++.这样就可以找到最靠后的满足要求的位置。

倍增的时候注意:如果不存在这么长的转移是不能够转移的,否则可能答案(步数)会算大。

代码

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch))	{if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
	return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=1e6 + 7,inf=0x3f3f3f3f;
int m,len,ans=inf;
int fa[N][21],mn[N];
struct data{
	int l,r;
	bool operator <(const data &rhs)const{
		if(r!=rhs.r) return r<rhs.r;
		return l<rhs.l;
	}
}t[N];
int main(){
	len=gi(),m=gi();
	rep(i,1,m) {
		t[i].l=gi(),t[i].r=gi();
		if(t[i].r<t[i].l) t[i].r+=len;
	}
	sort(t+1,t+1+m);
	mn[m+1]=inf;
	for(int i=m;i;i--) mn[i]=min(t[i].l,mn[i+1]);
	for(int i=1,j=1;i<=m;++i){
		while(j+1<=m&&mn[j+1]-1<=t[i].r)++j;
		if(i!=j) fa[i][0]=j;
	}
	for(int i=m;i;--i)
	for(int j=1;j<=20;++j) fa[i][j]=fa[fa[i][j-1]][j-1];
	
	for(int i=1;i<=m;++i){
		int s=1,x=i;
		for(int j=20;~j;--j) if(fa[x][j]&&t[fa[x][j]].r-t[i].l+1<len) x=fa[x][j],s+=1<<j;
		if(fa[x][0]&&t[x].r-t[i].l+1<len) ++s,x=fa[x][0];
		if(t[x].r-t[i].l+1>=len) Min(ans,s);
	}
	if(ans==inf) puts("impossible");
	else printf("%d\n",ans);
	return 0;
}
posted @ 2018-10-25 15:37  fwat  阅读(203)  评论(0编辑  收藏  举报