1. 程式人生 > >【CF875E】Delivery Club 二分+線段樹

【CF875E】Delivery Club 二分+線段樹

names turn body sort mod pri esp string etc

【CF875E】Delivery Club

題意:有n個快遞需要依次接收,這n個快遞分部在x軸上,第i個快遞的位置是xi。有兩個快遞員,一開始分別在s0,s1,你可以任意安排哪個人收哪個快遞,前提是一個快遞員收快遞是另一個快遞員不能移動(也就是說他只有在收快遞時能移動),並且要保證任何時候兩人的距離不超過k。問你k最小是多少。

n<=10^5,xi<=10^9

題解:二分是顯然的。我們可以用f[i][a][b]表示收第i個快遞時,兩個快遞員一個在a,一個在b是否可行,又因為a或b一定等於i,所以我們可以省掉一維。我們還可以用線段樹再省一維。因為在收第i+1個快遞時,要麽是在i處的快遞員走到i+1,此時與i+1距離超過k的位置a都變成了不合法的,可以用線段樹區間清零搞定;要麽是在a處的快遞員走到i+1。用線段樹很容易維護這些東西。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=100010;
int n;
int v[maxn],p[maxn],rnk[maxn];
bool s[maxn<<2];
inline int Abs(const int &a) {return a>0?a:-a;}
bool cmp(const int &a,const int &b)
{
	return v[a]<v[b];
}
inline void pushdown(int x)
{
	if(!s[x])	s[lson]=s[rson]=0;
}
void modify(int l,int r,int x,int a)
{
	if(l==r)
	{
		s[x]=1;
		return ;
	}
	pushdown(x);
	int mid=(l+r)>>1;
	if(a<=mid)	modify(l,mid,lson,a);
	else	modify(mid+1,r,rson,a);
	s[x]=s[lson]|s[rson];
}
void updata(int l,int r,int x,int a,int b)
{
	if(a>b)	return ;
	if(a<=l&&r<=b)
	{
		s[x]=0;
		return ;
	}
	pushdown(x);
	int mid=(l+r)>>1;
	if(a<=mid)	updata(l,mid,lson,a,b);
	if(b>mid)	updata(mid+1,r,rson,a,b);
	s[x]=s[lson]|s[rson];
}
bool check(int len)
{
	int i,l,r,mid;
	s[1]=0;
	modify(1,n,1,rnk[1]);
	for(i=3;i<=n;i++)
	{
		l=1,r=rnk[i];
		while(l<r)
		{
			mid=(l+r)>>1;
			if(v[p[mid]]<v[i]-len)	l=mid+1;
			else	r=mid;
		}
		updata(1,n,1,1,l-1);
		l=rnk[i],r=n;
		while(l<r)
		{
			mid=(l+r)>>1;
			if(v[p[mid]]<=v[i]+len)	l=mid+1;
			else	r=mid;
		}
		updata(1,n,1,l,n);
		if(Abs(v[i]-v[i-1])<=len)	modify(1,n,1,rnk[i-1]);
		if(!s[1])	return 0;
	}
	return 1;
}
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)	f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+(gc^‘0‘),gc=getchar();
	return ret*f;
}
int main()
{
	n=rd()+2;
	int i,l=0,r=0,mid;
	for(i=1;i<=n;i++)	v[i]=rd(),r=max(r,v[i]),p[i]=i;
	sort(p+1,p+n+1,cmp);
	for(i=1;i<=n;i++)	rnk[p[i]]=i;
	v[0]=-1000000000,v[n+1]=1000000000;
	l=Abs(v[2]-v[1]);
	while(l<r)
	{
		mid=(l+r)>>1;
		if(check(mid))	r=mid;
		else	l=mid+1;
	}
	printf("%d",r);
	return 0;
}

【CF875E】Delivery Club 二分+線段樹