【题解】[CJOI2019Chebnear]
题目描述
给定平面上有(n)个仇人,((x,y) ,x,y in R^+) ,(n)个人都是仇人关系,而有仇人关系的一对人的切比雪夫距离若(le k)则会发生“吵架”。可是,对于有些仇人(i)和(j),先记为三元组(P(t,i,w)),他们的的仇人关系并不深,假设给全体(n)个人每人(ge w)的钱他们就变为朋友了。而朋友不会吵架,而且朋友的朋友也是你的朋友。
现在问你,你最少给多少钱(w)可是让所有人不吵架?
数据范围
(nle100000,mle100000)
说明
切比雪夫距离:(d=max(|x_i-x_j|,|y_i-y_j|))
(Solution)
显然二分答案(w)。接下来的任务就是当给每个人(w)钱的时候,是否有人吵架了。
然后(O(m))枚举那些朋友可以连接,直接用并查集维护朋友关系。
考虑暴力。
- (O(n^2))枚举每个点对,看他们是否吵架。这样显然超时。
我们仔细思考一下,发现吵架只和以下两个因素有关。
- (y)安全但(x)距离过近。
- (x)安全但(y)距离过近。
- 朋友
朋友关系已经用并查集维护了,可以(O(alpha(n))=O(1))查询。接下来就是(x,y)的问题了。
考虑把所有点按(x)排序。这样我们就可以快速确定一段区间内的人是否有可能(x)过近,然后对于这些点(O(n_?^2))枚举是否会吵架就好了。
但是怎么缩小(n_?)呢?
对于平面最近点对问题,可以证明(n_? le 6)。这里我们也可以类比,每次和最近点对一样,直接从中间分开,分治。我们的(n_?)一定比最近点对的(n_?)还要小,因为我们还有(k)的限制呀,帮助我们剪枝。
接下来上代码了,今天的代码是不是码风很棒?
#include<bits/stdc++.h>
#define RP(t,a,b) for(register int (t)=(a),edd_=(b);t<=edd_;++t)
#define DRP(t,a,b) for(register int (t)=(a),edd_=(b);t>=edd_;--t)
#define ERP(t,a) for(int t=head[a];t;t=e[t].nx)
#define pushup(x) seg[(x)]=seg[(x)<<1]+seg[(x)<<1|1]
#define midd register int mid=(l+r)>>1
#define TMP template<class ccf>
#define rgt L,R,mid,r,pos<<1|1
#define lef L,R,l,mid,pos<<1
#define all 1,n,1
using namespace std;typedef long long ll;
TMP inline ccf Max(ccf a,ccf b){return a<b?b:a;}
TMP inline ccf Min(ccf a,ccf b){return a<b?a:b;}
TMP inline ccf Abs(ccf a){return a<0?-a:a;}
TMP inline ccf qr(ccf k){
char c=getchar();ccf x=0;int q=1;
while(c<48||c>57)q=c==45?-1:q,c=getchar();
while(c>=48&&c<=57)x=x*10+c-48,c=getchar();
return q==-1?-x:x;}
//-----------------template&IO------------------
int n,m;double k;
const int maxn=1e5+5;
struct node{
double x,y;int id;
inline bool operator <(node a){return x<a.x;}
inline double operator -(node a){return Max(Abs(x-a.x),Abs(y-a.y));}
}data[maxn];
struct E{
int fr,to;double w;
inline bool operator <(E a){return w<a.w;}
}e[maxn<<1];
int rr[maxn];
inline int q(int x){register int t=x,temp,i=x;
while(rr[t]!=t) t=rr[t];
while(rr[i]!=i) temp=rr[i],rr[i]=t,i=temp;
return t;
}
inline void j(int x,int y){rr[q(x)]=q(y);}
inline bool in(int x,int y){return q(x)==q(y);}
struct DFN{
double pos;int id;
inline bool operator <(DFN x){return pos<x.pos;}
}dfn[maxn];
bool divd(int lb,int rb){register int mid=(lb+rb)>>1;
if(lb>=rb) return 1;
if(!divd(lb,mid)) return 0;
if(!divd(mid+1,rb)) return 0;
register int L=mid,R=mid;
while(data[mid].x-data[L-1].x<=k&&L>lb) --L;
while(data[R+1].x-data[mid].x<=k&&R<rb) ++R;
RP(t,L,R)RP(i,t+1,R)
if(!in(data[t].id,data[i].id)&&data[t]-data[i]<=k)
return 0;
return 1;
}
inline bool chek(double x){
RP(t,1,n) rr[t]=t;
RP(t,1,m) if(x>=e[t].w) j(e[t].fr,e[t].to);
return divd(1,n);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("chebnear.in","r",stdin);
freopen("chebnear.out","w",stdout);
#endif
cin>>n>>m>>k;
RP(t,1,n)
cin>>data[t].x>>data[t].y,data[t].id=t;
RP(t,1,m)
cin>>e[t].fr>>e[t].to>>e[t].w;
sort(data+1,data+n+1);
sort(e+1,e+m+1);
int l=1,r=m,ans=m;
do{
midd;
if(chek(e[mid].w))
r=mid-1,ans=Min(ans,mid);
else
l=mid+1;
}while(l<=r);
if(chek(0)) ans=0;
printf("%.3lf
",e[ans].w);
return 0;
}