题解 P2778 【[AHOI2016初中组]迷宫】
笔者的做法和下面几篇题解是一样的,在这里就不重复叙述了。这里介绍一下官方给出的做法。
题目分析
把平面上每一个区域看作一个结点,最外层没有边界的区域也看作一个结点。如果一个区域刚好被另外一个区域直接包含,则连边。构成的图上做最短路径即可以得到40~60的分数。
又发现,上述得到的图是树结构的,在树上预处理好任意两点的最近公共祖先,之后的询问可以线形完成,这便可以得到满分。
std
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
struct Point
{
ll x,y;
Point(){}
Point(ll _x,ll _y):x(_x),y(_y){}
Point operator - (const Point &t)const
{
return Point(x-t.x,y-t.y);
}
ll len2()
{
return x*x+y*y;
}
};
struct Circle
{
Point o;
ll r;
Circle(){}
Circle(Point _o,ll _r):o(_o),r(_r){}
bool operator < (const Circle &t)const
{
return r<t.r;
}
bool contain(Point t)
{
return (t-o).len2()<r*r;
}
}c[8005];
struct Edge
{
int to,nxt;
}edge[8005];
int head[8005],tot;
void init()
{
memset(head,-1,sizeof(head));
tot=0;
}
void addedge(int u,int v)
{
edge[tot].to=v;
edge[tot].nxt=head[u];
head[u]=tot++;
}
int fa[8005],dep[8005];
void dfs(int u,int la)
{
fa[u]=la;
dep[u]=(la>=0 ? dep[la]+1 : 0);
for(int i=head[u];~i;i=edge[i].nxt)
dfs(edge[i].to,u);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%lld%lld%lld",&c[i].o.x,&c[i].o.y,&c[i].r);
c[n++]=Circle(Point(0,0),200000000);
sort(c,c+n);
init();
for(int i=0;i<n-1;i++)
for(int j=i+1;j<n;j++)
if(c[j].contain(c[i].o))
{
addedge(j,i);
break;
}
dfs(n-1,-1);
int m;
scanf("%d",&m);
for(int i=0;i<m;i++)
{
int u[2];
for(int j=0;j<2;j++)
{
Point p;
scanf("%lld%lld",&p.x,&p.y);
for(int k=0;k<n;k++)
if(c[k].contain(p))
{
u[j]=k;
break;
}
}
int res=0;
while(u[0]!=u[1])
{
if(dep[u[0]]>dep[u[1]])u[0]=fa[u[0]];
else u[1]=fa[u[1]];
res++;
}
printf("%d\n",res);
}
return 0;
}
吐槽
这玩意又难写,常数又大(原题时限5s),不知道出题人怎么想到的。