**开始天真的我以为这道题和运输计划是一样的套路。于是写了一发,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;
}