[51Nod1671] 货物运输

题意:给出1~n个点,i与i+1有权为1的边,有m个任务同时进行,你可以使用洪荒之力开一个传送门使某个点x到某个点y不需要代价,求完成所有任务的最小代价

题解:

二分+思维

嗯,如果抛开二分,这题基本上就是个纯思维题,乍一看很想运输计划的弱化版,但是运输计划断的是一条边,而这个题则是一条路径

二分最大路径长度,记下所有大于mid的路径,设传送门为(x,y),则这些路径的路线必定是:l -> x -> y -> r

于是我们考虑枚举x,对于某个任务,得出y的范围:mid-(abs(l-x))>=abs(y-r) -> r-mid+abs(l-x)<=y<=r+mid-abs(l-x)

于是得出了每个位置的x对于每个任务的y的范围,则问题转化判断所有的y是否有交

拆开上面式子的绝对值,发现需要分x<l和l<=x两种情况讨论,因为x是共有的未知项,所以只是比较大小的话可以忽略

那么可以预处理忽略掉x的y,最后判断是否有交即可

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;

const int N = 500010;

int n,m,L,ans=1<<30,l1[N],r1[N];

struct Node {
  int l,r;
  bool operator < (const Node &x) const {
    return l<x.l;
  }
}p[N];

struct Dat {int l,r,l1,r1,l2,r2;}q[N];

int gi() {
  int x=0,o=1; char ch=getchar();
  while(ch!='-' && (ch<'0' || ch>'9')) ch=getchar();
  if(ch=='-') o=-1,ch=getchar();
  while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
  return o*x;
}

bool check(int mid) {
  int cnt=0,top,l2,r2;
  for(int i=1; i<=m; i++) {
    if(p[i].r-p[i].l>mid) {
      cnt++;
      q[cnt].l=p[i].l,q[cnt].r=p[i].r;
      q[cnt].l1=p[i].r-mid+p[i].l,q[cnt].r1=p[i].r+mid-p[i].l;//l>x
      q[cnt].l2=p[i].r-mid-p[i].l,q[cnt].r2=p[i].r+mid+p[i].l;//l<=x
    }
  }
  l1[n+1]=l2=-1<<30,r1[n+1]=r2=1<<30,top=cnt;
  for(int i=n; i>=1; i--) {
    l1[i]=l1[i+1],r1[i]=r1[i+1];
    while(top && q[top].l>i) {
      l1[i]=max(l1[i],q[top].l1);
      r1[i]=min(r1[i],q[top].r1);
      top--;
    }
  }
  top=1;
  for(int i=1; i<=n; i++) {
    while(top<=cnt && q[top].l<=i) {
      l2=max(l2,q[top].l2);
      r2=min(r2,q[top].r2);
      top++;
    }
    if(l1[i]-i<=r1[i]+i && l2+i<=r2-i) {
      if(r1[i]+i>=l2+i && l1[i]-i<=r2-i) return true;
    }
  }
  return false;
}

int main() {
  n=gi(),m=gi();
  for(int i=1; i<=m; i++) {
    int x=gi(),y=gi();
    p[i].l=min(x,y),p[i].r=max(x,y);
    L=max(L,p[i].r-p[i].l);
  }
  sort(p+1,p+m+1);
  int l=0,r=L,mid;
  while(l<=r) {
    mid=(l+r)>>1;
    if(check(mid)) ans=min(ans,mid),r=mid-1;
    else l=mid+1;
  }
  printf("%d", ans);
  return 0;
}
原文地址:https://www.cnblogs.com/HLXZZ/p/7527185.html