• 51nod1671【货物运输】


    **开始天真的我以为这道题和运输计划是一样的套路。于是写了一发,debug后发现过了第一个点,十分开心的交了一发,结果只过了第一个点。后来发现这个并不是一样的,因为修建黑洞之后路径法变了,而运输计划没有(树上两点间路径唯一)。于是,第一题就成了题解题...
    这道题显然满足二分性质。问题在与如何判断合法。
    首先,(<=mid) 的路径肯定满足,对于不满足的路径 (l)(r),一定是在 (x)(y) 处修建黑洞以后,(l) -> (x) -> (y) -> (r),且满足不等式:

    [left | l-x ight | + left | r-y ight | <= mid ]

    解得:

    [yinleft [ l+r-mid+x,r-l+mid-x ight ]left ( l>=x ight ) ]

    [yinleft [ r-l-mid+x,r+l+mid-x ight ]left ( l<x ight ) ]

    暴力的做法是枚举 (x),对于每一个区间求出 (y) 的取值范围,然后判断是否有交集。
    但这样是 (O(n^2)) 的,需要优化。可以把区间分成两部分,前一部分 (l<x),后一部分 (l>=x),在两个部分分别求交集,再两部分的交集判断是否有交集。这样的话,前一部分的区间都有一个增量 (x),交集就是 (l+r-mid) 的交集再加上 (x),对于 (l+r-mid) 的交集可以 (O(n)) 预处理。后一部分同理。前一部分预处理处理前缀,后一部分后缀。
    然后就可以 (O(1)) 判断两部分的交集是否有交集。**

    #include <bits/stdc++.h>
    using namespace std;
    
    #define db double
    #define ll long long
    #define RG register
    
    inline int gi()
    {
    	RG int ret; RG bool flag; RG char ch;
    	ret=0, flag=true, ch=getchar();
    	while (ch < '0' || ch > '9')
    		ch == '-' ? flag=false : 0, ch=getchar();
    	while (ch >= '0' && ch <= '9')
    		ret=(ret<<3)+(ret<<1)+ch-'0', ch=getchar();
    	return flag ? ret : -ret;
    }
    
    const db pi = acos(-1.0);
    const int N = 5e5+5, inf = 1<<30;
    
    int n,m,cf[N],l1[N],r1[N];
    struct range
    {
    	int l,r;
    	inline bool operator <(const RG range &R) const { return l < R.l; }
    }ra[N];
    struct Range
    {
    	int l,r,l1,l2,r1,r2;
    }g[N];
    
    inline bool check(RG int lim)
    {
    	RG int i,cnt,p,l2,r2;
    	cnt=0;
    	for (i=1; i<=m; ++i)
    		{
    			if (ra[i].r-ra[i].l <= lim)
    				continue;
    			cnt++;
    			g[cnt].l=ra[i].l, g[cnt].r=ra[i].r;
    			g[cnt].l1=ra[i].l+ra[i].r-lim;
    			g[cnt].l2=ra[i].r-ra[i].l-lim;
    			g[cnt].r1=ra[i].r-ra[i].l+lim;
    			g[cnt].r2=ra[i].l+ra[i].r+lim;
    		}  //预处理
    	p=cnt;
    	l1[n+1]=l2=-inf, r1[n+1]=r2=inf;
    	for (i=n; i; --i)
    		{
    			l1[i]=l1[i+1], r1[i]=r1[i+1];
    			while (p && g[p].l >= i)
    				{
    					l1[i] < g[p].l1 ? l1[i]=g[p].l1 : 0;
    					r1[i] > g[p].r1 ? r1[i]=g[p].r1 : 0;
    					p--;
    				}
    		}  //预处理对于每一个x后一部分的解集
    	p=1;
    	for (i=1; i<=n; ++i)
    		{
    			while (p <= cnt && g[p].l <= i)
    				{
    					l2 < g[p].l2 ? l2=g[p].l2 : 0;
    					r2 > g[p].r2 ? r2=g[p].r2 : 0;
    					p++;
    				}  //计算对于每一个x前一部分的解集
    			if (l1[i] <= r1[i]+(i<<1) && l2+(i<<1) <= r2
    				 && !((r1[i] < l2) || (l1[i] > r2)))
    				return true;  //判断前后是否分别有解及两部分是否有交集
    		}
    	return false;
    }
    
    int main()
    {
    	freopen("trans.in","r",stdin);
    	freopen("trans.out","w",stdout);
    	n=gi(), m=gi();
    	RG int i,l,r,mid;
    	for (i=1; i<=m; ++i)
    		{
    			ra[i].l=gi(), ra[i].r=gi();
    			if (ra[i].l > ra[i].r)
    				swap(ra[i].l,ra[i].r);
    		}
    	sort(ra+1,ra+m+1);
    	l=0, r=n+1;
    	while (l <= r)
    		{
    			mid=(l+r)>>1;
    			if (check(mid))
    				r=mid-1;
    			else
    				l=mid+1;
    		}
    	printf("%d
    ",r+1);
    	return 0;
    }
    
  • 相关阅读:
    抽象类和接口的区别
    排序之快速排序(quickSort)
    互联网协议入门(1)
    字符串的操作String
    Java笔试题之SQL语句(单表)
    求职之Java开发所需技能
    【更新完毕啦!】一篇完整的产品体验报告处女作
    阿里2015暑期实习生业务型产品笔试题(附部分参考答案)
    滴滴笔试题(附我的答案)
    【面试】蘑菇街产品运营二面&结果
  • 原文地址:https://www.cnblogs.com/y142857/p/7525271.html
Copyright © 2020-2023  润新知