您的位置:首页 > 其它

jzoj【NOIP2017提高A组冲刺11.3】高考是不可能高考的

2017-11-03 16:35 489 查看

题目

Time Limits: 2000 ms Memory Limits: 1048576 KB

Description

Snuke 喜欢旗子.

Snuke 正在将N 个旗子摆在一条线上.

第i 个旗子可以被放在位置xi 或yi 上.

Snuke 认为两个旗子间的最小距离越大越好. 请你求出最大值.

Input

N

x1 y1



xN yN

Output

输出一行一个整数表示答案.

Sample Input

输入1:

3

1 3

2 5

1 9

输入2:

5

2 2

2 2

2 2

2 2

2 2

输入3:

22

93 6440

78 6647

862 11

8306 9689

798 99

801 521

188 206

6079 971

4559 209

50 94

92 6270

5403 560

803 83

1855 99

42 504

75 484

629 11

92 122

3359 37

28 16

648 14

11 269

Sample Output

输出1:

4

输出2:

0

输出3:

17

Data Constraint

对于30% 的数据, N <=18;

对于60% 的数据, N <=1000;

对于100% 的数据, 1 <= N <= 10^4; 1 <= xi, yi <= 10^9.

题解

2-set的连边:如果选了一个点后不能选另一个点,那么就在那个点对应的另一个点连一条单向边

考虑2-set

一个比较显然的思路是我们可以二分答案,然后用2-set判断可行性

但是这样会超时

我们可以先把所有的点排序,然后就可以比较快的连边了,我们还可以事先搞一个较小的上界,也就是对两个点对中最远的点对的距离的最小值

但是这只是一个水法

我们有一个很优秀的算法

我们可以对a,b分别排序,然后建两颗线段树,然后对于一个点,它可以连的边就是线段树中对应的连续的一段点,那么我们不妨连到那个子树的根,对线段树我们从上往下连一些单向边就好了

这样我们就可以用n log n级别的点数和边树完成对图的构造了,然后我们对这个图跑一下2-set就好了

贴代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)

using namespace std;

const int maxn=2e4+5,cs=3e7+5;

struct P{
int x,y;
}a[maxn];
int fi[maxn*2],ne[cs*2],dui[cs*2],qc[cs*2];
bool bb[maxn*2],bz[maxn*2];
int dfn[maxn],low[maxn],st[maxn],cc[maxn];
int i,j,k,l,r,n,m,x,y,ma,mid,nc,cq,tp,now;

int cmp(P x,P y){
return x.x<y.x;
}
void add(int x,int y){
if (fi[x]==0) fi[x]=++now; else ne[qc[x]]=++now;
qc[x]=now; dui[now]=y;
}
void ge_bian(){
fo(i,1,now) ne[i]=0;
now=0;
memset(fi,0,sizeof(fi));
fo(i,1,2*n){
j=i-1;
while (j>0 && a[i].x-a[j].x<mid){
if (abs(a[i].y-a[j].y)!=n){
if (a[j].y>n) add(a[i].y,a[j].y-n); else add(a[i].y,a[j].y+n);
}
j--;
}
j=i+1;
while (j<=2*n && a[j].x-a[i].x<mid){
if (abs(a[i].y-a[j].y)!=n){
if (a[j].y>n) add(a[i].y,a[j].y-n); else add(a[i].y,a[j].y+n);
}
j++;
}
}
}
void tarjan(int x){
dfn[x]=low[x]=++cq; bz[x]=true; bb[x]=true;
st[++tp]=x;
int i=fi[x];
while (i){
if (bz[dui[i]]==false){
tarjan(dui[i]);
low[x]=min(low[x],low[dui[i]]);
} else if (bb[dui[i]]==true) low[x]=min(low[x],low[dui[i]]);
i=ne[i];
}
if (dfn[x]==low[x]){
nc++;
while (true){
cc[st[tp]]=nc;
bb[st[tp]]=false;
tp--;
if (st[tp+1]==x) break;
}
}
}
bool check(){
memset(bz,false,sizeof(bz));
memset(bb,false,sizeof(bb));
memset(cc,0,sizeof(cc));
nc=cq=tp=0;
fo(i,1,2*n)
if (bz[i]==false) tarjan(i);
fo(i,1,n) if (cc[i]==cc[i+n]) return false;
return true;
}
int main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&n);
ma=0x7fffffff;
fo(i,1,n){
scanf("%d%d",&x,&y);
a[i].x=x; a[i].y=i;
a[i+n].x=y; a[i+n].y=i+n;
fo(j,1,i-1){
x=max(abs(a[i].x-a[j].x),abs(a[i].x-a[j+n].x));
y=max(abs(a[i+n].x-a[j].x),abs(a[i+n].x-a[j+n].x));
ma=min(ma,max(x,y));
}
}
sort(a+1,a+n*2+1,cmp);
fo(i,1,2*n) dui[a[i].y]=i;
l=1;
r=ma;
while (l<r){
mid=(l+r)/2;
ge_bian();
if (check()) l=mid+1; else r=mid;
}
mid=l;
ge_bian(); if (check()==false) l--;
printf("%d\n",l);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: