【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; }