标签:stream amp print 转化 har logs clu operator efi
题意:给出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;
}
标签:stream amp print 转化 har logs clu operator efi
原文地址:http://www.cnblogs.com/HLXZZ/p/7527185.html