zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    第十三周
    意见评论
    第十二周
    冲刺10
    冲刺9
    冲刺8
    团队冲刺第二十二天-KeepRunningAPP
    找水王
    第十四周总结
    搜狗输入法评价
  • 原文地址:https://www.cnblogs.com/HLXZZ/p/7527185.html
Copyright © 2011-2022 走看看