[USACO18JAN] Lifeguards S

题目描述
FJ为他的奶牛们建造了一个游泳池,FJ认为这将有助于他们放松身心以及生产更多牛奶。

为了确保奶牛们的安全,FJ雇佣了N头牛,作为泳池的救生员,每一个救生员在一天内都会有一定的事情,并且这些事情都会覆盖一天内的一段时间。为了简单起见,泳池从时间t=0时开门,直到时间t=1000000000关门,所以每个事情都可以用两个整数来描述,给出奶牛救生员开始以及结束事情的时间。例如,一个救生员在时间t=4时开始事情并且在时间t=7时结束事情,那么这件事情就覆盖了3个单位时间。(注意:结束时间是“点”的时间)

不幸的是,FJ多雇佣了一名的救生员,但他没有足够的资金来雇佣这些救生员。因此他必须解雇一名救生员,求可以覆盖剩余救生员的轮班时间的最大总量是多少?如果当时至少有一名救生员的事情已经开始,则这个时段被覆盖。

输入格式

输入的第一行包括一个整数N(1≤N≤100000)。接下来N行中,每行告诉了我们一个救生员在0~10000000000范围内的开始以及结束时间。所有的结束时间都是不同的。不同的救生员的事情覆盖的时间可能会重叠。

输出格式

如果FJ解雇一名救生员仍能覆盖的最大时间。

因为坐标的范围很大,所以我们需要离散化一下

我们可以把问题转化一下,转化成,我们要找一个救生员,在他在的时间段内,他一个人独自在的时间最小(好绕嘴啊)

这个问题可以用差分+线段树(树状数组)解决

我们离散化后建立差分数组 c f cf

对于一个看守区间为 [ l , r ] [l,r] 的救生员,我们把CF l + 1 _l+1 ,CF r 1 _r-1 ,注意这里不是 r + 1 r+1 的位置-1,因为离散化之后每个值都相当于他区间的左端点了

差分完之后我们从左往右扫一遍,把每一个只有一个人的点加上他这个点所代表的长度存到线段树(树状数组)里面,对于每一个救生员,他单独存在的时间就是线段树(树状数组)中这一区间的和

然后再求一下总共用的时间就可以了

代码(线段树):

# include <cstdio>
# include <algorithm>
# include <cstring>
# include <cmath>
# include <climits>
# include <iostream>
# include <string>
# include <queue>
# include <stack>
# include <vector>
# include <set>
# include <map>
# include <cstdlib>
# include <ctime>
using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;
const int N=1e6+5;
const int inf=0x7fffffff;
const double eps=1e-7;
template <typename T> void read(T &x){
	x=0;int f=1;
	char c=getchar();
	for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
	for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
	x*=f;
}

# define int long long

int n,sz,ans=INT_MAX;
int b[N<<1];
int cf[N<<1];

struct guards{
	int l,r;	
}q[N];

struct segment_tree{
	int l,r,val;	
}seg[N<<2];

# define lc (u<<1)
# define rc (u<<1|1)

void build(int u,int l,int r){
	seg[u].l=l,seg[u].r=r;
	seg[u].val=0;
	if(l==r)return;
	int mid=l+r>>1;
	build(lc,l,mid);
	build(rc,mid+1,r);
}

void update(int u,int x,int k){
	if(seg[u].l==seg[u].r){seg[u].val+=k;return;}
	int mid=seg[u].l+seg[u].r>>1;
	if(x<=mid)update(lc,x,k);
	else update(rc,x,k);
	seg[u].val=seg[lc].val+seg[rc].val;	
}

int query(int u,int l,int r){
	if(seg[u].l>=l&&seg[u].r<=r)return seg[u].val;
	int mid=seg[u].l+seg[u].r>>1;
	int res=0;
	if(l<=mid)res+=query(lc,l,r);
	if(r>mid)res+=query(rc,l,r);
	return res;	
}

signed main()
{
	read(n);
	Rep(i,1,n){
		read(q[i].l),read(q[i].r);
		b[i]=q[i].l;
		b[i+n]=q[i].r;	
	}
	sort(b+1,b+2*n+1);
	sz=unique(b+1,b+2*n+1)-b-1;
	Rep(i,1,n){
		q[i].l=lower_bound(b+1,b+sz+1,q[i].l)-b;
		q[i].r=lower_bound(b+1,b+sz+1,q[i].r)-b;	
	}
	build(1,1,sz);
	Rep(i,1,n){
		cf[q[i].l]++;
		cf[q[i].r]--;	
	}
	int d=0;
	Rep(i,1,sz){
		d+=cf[i];
		if(d==1){
			int k=i;
			while(cf[k+1]==0)k++;
			update(1,i,b[k+1]-b[i]);	
		}
	}
	Rep(i,1,n)ans=min(ans,query(1,q[i].l,q[i].r-1));
	ans=-ans;
	d=0;
	Rep(i,1,sz){
		d+=cf[i];
		if(d>0)ans+=b[i+1]-b[i];	
	}
	printf("%d\n",ans);
	return 0;
}	
发布了21 篇原创文章 · 获赞 8 · 访问量 1615

猜你喜欢

转载自blog.csdn.net/devout_/article/details/104088670
今日推荐