[BalticOI 2016 day1]Park(并查集+计算几何)
作者:互联网
[BalticOI 2016 day1]Park(并查集+计算几何)
题面
在 Byteland 的首都,有一个以围墙包裹的矩形公园,其中以圆形表示游客和树。
公园里有四个入口,分别在四个角落(1, 2, 3, 4)分别对应左下、右下、左上、右上)。游客只能从入口进出。
游客可以在他们与公园的两邻边相切的时候进出对应的出口。游客可以在公园里自由活动但不允许与树重叠。
给出\(n\)棵树和\(m\)个游客,你的任务是为每个游客计算,给定他们进入公园的入口,他们可以从哪个入口离开公园。
\(n \leq 2000,m \leq 10^5\)
分析
我们反过来考虑,求出每两个口间可以通过的圆的半径的最大值。
把每棵树和公园的4个边界看成点,把任意两者间可以通过的半径作为边权建图。如果图上存在一条连接两个边界的路径,使得路径上边权都$\leq $游客的半径,那么游客就不能通过。具体是哪些边界取决于游客的起点和终点。
那么我们将询问离线,并按照半径从小到大排序.同时也将边权从小到大排序。将小于当前半径\(\times 2\)的边加入,那么就可以根据上面的方法判断是否联通。对于每一对出入口分类讨论,建议自己画图观察。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 4000000
#define maxm 100000
using namespace std;
typedef long long db;
int n,m;
db W,H;
struct circle{
db x;
db y;
db r;
}c[maxn+5];
struct edge{
int from;
int to;
db len;
friend bool operator < (edge p,edge q){
return p.len<q.len;
}
}E[maxn+5];
int esz=1;
void add_edge(int u,int v,db w){
esz++;
E[esz].from=u,E[esz].to=v,E[esz].len=w;
}
struct qry{
int id;
int pos;
db r;
friend bool operator < (qry p,qry q){
return p.r<q.r;
}
}q[maxm+5];
inline db dist(db x1,db y1,db x2,db y2){
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
struct DSU{
int fa[maxn+5];
int find(int x){
if(fa[x]==x) return x;
else return fa[x]=find(fa[x]);
}
inline void merge(int x,int y){
fa[find(x)]=find(y);
}
inline void ini(int n){
for(int i=1;i<=n;i++) fa[i]=i;
}
}S;
inline bool ok(int x,int y){
//不能通过,即两个边界对应的点被中间长度>2r边连通
//能通过反之
return S.find(n+x)!=S.find(n+y);
}
int ans[maxn+5][5];
int main(){
#ifndef LOCAL
freopen("corner.in","r",stdin);
freopen("corner.out","w",stdout);
#endif
scanf("%d %d %lld %lld",&n,&m,&W,&H);
for(int i=1;i<=n;i++) scanf("%lld %lld %lld",&c[i].x,&c[i].y,&c[i].r);
for(int i=1;i<=m;i++){
scanf("%lld %d",&q[i].r,&q[i].pos);
q[i].id=i;
}
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
add_edge(i,j,dist(c[i].x,c[i].y,c[j].x,c[j].y)-c[i].r-c[j].r);
}
add_edge(i,n+1,c[i].x-c[i].r);//n+1,n+2,n+3,n+4 ->左,下,右,上
add_edge(i,n+2,c[i].y-c[i].r);
add_edge(i,n+3,W-c[i].x-c[i].r);
add_edge(i,n+4,H-c[i].y-c[i].r);
}
S.ini(n+4);
sort(E+1,E+1+esz);
sort(q+1,q+1+m);
int ptr=0;
for(int i=1;i<=m;i++){
while(ptr<esz&&E[ptr+1].len<q[i].r*2){
ptr++;
S.merge(E[ptr].from,E[ptr].to);
}
int id=q[i].id,pos=q[i].pos;
ans[id][pos]=1;
if(pos==1){
if(ok(1,2)&&ok(2,4)&&ok(2,3)) ans[id][2]=1;
if(ok(1,2)&&ok(2,4)&&ok(1,3)&&ok(3,4)) ans[id][3]=1;
if(ok(1,2)&&ok(1,3)&&ok(1,4)) ans[id][4]=1;
}else if(pos==2){
if(ok(1,2)&&ok(2,3)&&ok(2,4)) ans[id][1]=1;
if(ok(2,3)&&ok(1,3)&&ok(3,4)) ans[id][3]=1;
if(ok(2,3)&&ok(1,3)&&ok(2,4)&&ok(1,4)) ans[id][4]=1;
}else if(pos==3){
if(ok(3,4)&&ok(1,3)&&ok(2,4)&&ok(1,2)) ans[id][1]=1;
if(ok(3,4)&&ok(1,3)&&ok(2,3)) ans[id][2]=1;
if(ok(3,4)&&ok(2,4)&&ok(1,4)) ans[id][4]=1;
}else{
if(ok(1,4)&&ok(1,3)&&ok(1,2)) ans[id][1]=1;
if(ok(1,4)&&ok(2,4)&&ok(1,3)&&ok(2,3)) ans[id][2]=1;
if(ok(1,4)&&ok(2,4)&&ok(3,4)) ans[id][3]=1;
}
}
for(int i=1;i<=m;i++){
for(int j=1;j<=4;j++) if(ans[i][j]) printf("%d",j);
printf("\n");
}
}
标签:公园,int,Park,查集,db,day1,游客,edge,include 来源: https://www.cnblogs.com/birchtree/p/14061574.html