题意简述

给定一个正\(n\)边形及其三角剖分,每条边的长度为\(1\),给你\(q\)组询问,每次询问给定两个点\(x_i\)至\(y_i\)的最短距离。

做法

显然正多边形的三角剖分是一个平面图,每一条剖分的边可以将正多边形分成有一条重边的两个独立的新多边形,显然这一个过程是可以用分治来实现的。

我们对于分治过程中的多边形进行重新编号,找到两端点数最平均的边割去,对于点集\(V\),边集\(E\)和询问集\(Q\)分别开三个vector传入函数中。

如果点集的大小等于了\(3\),我们就可以对单个三角形进行直接计算,否则对于集合进行左右的分治,贡献大小使用两次bfs计算,时间复杂度\(O(n \log{n})\)。

代码实现

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define in inline
#define ll long long
#define ak *
#define db double
in char getch()
{
static char buf[1<<12],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;
}
char qwq;
#define gc() getch()
in int read()
{
re cz=0,ioi=1;qwq=gc();
while(qwq<'0'||qwq>'9') ioi=qwq=='-'?~ioi+1:1,qwq=gc();
while(qwq>='0'&&qwq<='9') cz=(cz<<3)+(cz<<1)+(qwq^48),qwq=gc();
return cz ak ioi;
}
#define vec vector
#define pb push_back
const int N=6e4+5;
int n,m,h[N],cnt,dx[N],dy[N],ans[N<<1],siz[N],le[N],ri[N],vis[N];
struct did{int next,to;}e[N<<2];
struct edge{int u,v;};
struct que{int a,b,id;};
vec<edge>ed;
vec<que>qr;
vec<int>ve;
in void Add(re x,re y) {e[++cnt]=(did){h[x],y},h[x]=cnt;}
in void add(re x,re y) {Add(x,y);Add(y,x);}
queue<int>q;
in void bfs(re s,re *dis)
{
dis[s]=0;q.push(s);
while(!q.empty())
{
re u=q.front();q.pop();
for(re i=h[u],v;v=e[i].to,i;i=e[i].next)
if(dis[v]>=1e9&&vis[v]) dis[v]=dis[u]+1,q.push(v);
}
}
void divide(vec<int>v,vec<edge>ed,vec<que>qr)
{
if(!qr.size()) return;
if(v.size()==3)
{
for(re i=0;i<qr.size();i++)
ans[qr[i].id]=((qr[i].a==qr[i].b)^1);
return;
}
vec<int>v1,v2;v1.clear(),v2.clear();
vec<edge>e1,e2;e1.clear(),e2.clear();
vec<que>q1,q2;q1.clear(),q2.clear();
re n=v.size(),m=ed.size();
for(re i=0;i<n;i++) siz[v[i]]=0;siz[v[0]]=1;
for(re i=1;i<n;i++) siz[v[i]]=siz[v[i-1]]+1;
re x=0,y=0,minn=1e9;
for(re i=0;i<m;i++)
{
re u=ed[i].u,v=ed[i].v,len=siz[v]-siz[u]-1;
if(max(len,n-2-len)<minn)
minn=max(len,n-2-len),x=u,y=v;
}
for(re i=0;i<n;i++)
{
if(v[i]>=x&&v[i]<=y) le[v[i]]=1,v1.pb(v[i]);
if(v[i]<=x||v[i]>=y) ri[v[i]]=1,v2.pb(v[i]);
}
for(re i=0;i<m;i++)
{
re u=ed[i].u,v=ed[i].v;
if(le[u]&&le[v]) e1.pb(ed[i]);
if(ri[u]&&ri[v]) e2.pb(ed[i]);
}
for(re i=0;i<qr.size();i++)
{
re a=qr[i].a,b=qr[i].b;
if(le[a]&&le[b]) q1.pb(qr[i]);
if(ri[a]&&ri[b]) q2.pb(qr[i]);
}
for(re i=0;i<n;i++) vis[v[i]]=1,dx[v[i]]=dy[v[i]]=1e9;
bfs(x,dx);bfs(y,dy);
for(re i=0;i<qr.size();i++)
{
re a=qr[i].a,b=qr[i].b,id=qr[i].id;
re lenx=dx[a]+dx[b],leny=dy[a]+dy[b];
ans[id]=min(min(ans[id],min(lenx,leny)),min(dx[a]+dy[b],dx[b]+dy[a])+1);
}
for(re i=0;i<n;i++) vis[v[i]]=le[v[i]]=ri[v[i]]=0;
divide(v1,e1,q1);divide(v2,e2,q2);
}
int main()
{
freopen("bsh.in","r",stdin);
freopen("bsh.out","w",stdout);
n=read();
for(re i=1;i<=n;i++) add(i,i+1-n*(i==n));
for(re i=1;i<=n-3;i++)
{
re x=read(),y=read();
add(x,y);if(x>y) swap(x,y);
ed.pb((edge){x,y});
}
for(re i=1;i<=n;i++) ve.pb(i);
m=read();
for(re i=1;i<=m;i++)
{
re x=read(),y=read();
if(x>y) swap(x,y);
qr.pb((que){x,y,i});
}
memset(ans,127,sizeof(ans));
divide(ve,ed,qr);
for(re i=1;i<=m;i++) printf("%d\n",ans[i]);
}

BSOJ5458 [NOI2018模拟5]三角剖分Bsh 分治最短路的更多相关文章

  1. 【NOI2018模拟5】三角剖分Bsh

    [NOI2018模拟5]三角剖分Bsh Description 给定一个正 n 边形及其三角剖分,共 2n - 3 条边 (n条多边形的边和n-3 条对角线),每条边的长度为 1. 共 q 次询问,每 ...

  2. JZOJ 5602.【NOI2018模拟3.26】Cti

    JZOJ 5602.[NOI2018模拟3.26]Cti Description 有一个 \(n×m\) 的地图,地图上的每一个位置可以是空地,炮塔或是敌人.你需要操纵炮塔消灭敌人. 对于每个炮塔都有 ...

  3. 【NOI2018模拟】Yja

    [NOI2018模拟]Yja Description 在平面上找\(n\)个点,要求这 \(n\)个点离原点的距离分别为 \(r1,r2,...,rn\) .最大化这\(n\) 个点构成的凸包面积,凸 ...

  4. JZOJ 3470. 【NOIP2013模拟联考8】最短路(path)

    470. [NOIP2013模拟联考8]最短路(path) (Standard IO) Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed ...

  5. 【JZOJ5605】【NOI2018模拟3.26】Arg

    题目描述 给出一个长度为 m 的序列 A, 请你求出有多少种 1...n 的排列, 满足 A 是它的一个 LIS. 解题思路 如何求出一个序列的LIS? 对于二分的方法,每次插入一个数,将它放到第一个 ...

  6. 7.6 NOI模拟赛 灯 根号分治

    比较容易想的题目~ 容易发现 点亮一种颜色的贡献=新增灯的数量-已经存在的边的条数. 用线段树维护并不容易.暴力的话复杂度是\(Q\cdot n\)的. 考虑根号分治 只单纯考虑度数<B的点的话 ...

  7. 5.15 省选模拟赛 T1 点分治 FFT

    LINK:5.15 T1 对于60分的暴力 都很水 就不一一赘述了. 由于是询问所有点的这种信息 确实不太会. 想了一下 如果只是询问子树内的话 dsu on tree还是可以做的. 可以自己思考一下 ...

  8. 【JZOJ5603】【NOI2018模拟3.27】Xjz

    题目描述 给定字符串 S 和 T. 串A和串B匹配的定义改为:存在一个字符的映射,使得A应用这个映射之后等于B,且这个映射必须为一个排列. A=121, B=313,当映射为{1->3, 2-& ...

  9. 【BZOJ-4456】旅行者 分治 + 最短路

    4456: [Zjoi2016]旅行者 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 254  Solved: 162[Submit][Status] ...

随机推荐

  1. 关于自定义 List集合排序的方法!

    大致流程: 排序是用到排序的接口Comparator<T>你要先建一个类实现比较器Comparator //大致流程public class StuComp implements Comp ...

  2. Openstack 实现技术分解 (3) 开发工具 — VIM & dotfiles

    目录 目录 前文列表 扩展阅读 前言 插件管理 Vundle 主题 Solarized 浏览项目目录结构 Nerdtree Symbol 窗口 Tagbar 文件模糊查询 CtrlP 代码补全 You ...

  3. Linux_进程管理&计划任务

    目录 目录 top打开Linux系统任务管理控制台 ps进程查询指令 kill进程关闭指令 一个小实验 一次性计划任务 周期性计划任务 top打开Linux系统任务管理控制台 快捷键: P M k q ...

  4. laravel 添加后台登陆守护器

    后台不能在一个浏览器登陆,下面简单配置下即可解决这个问题. 设置路由如下: <?php /** * 后台路由,从Illuminate\Routing\Router控制器的auth()方法中复制过 ...

  5. pg和mysql对比

    作者:方圆链接:https://www.zhihu.com/question/20010554/answer/15863274来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出 ...

  6. P站图片下载工具。

    下载 Pixiv 的图片比较麻烦,就做了这么个东西. 主要就是用 HttpWebRequest HttpWebResponse 下载了网页的 html 代码然后截取里面的内容.代码上传到了文件里. p ...

  7. JSP———数据交互【1】

    JSP的内置对象 不用声明就可以在JSP页面中使用 request对象 内置对象 request 封装了用户提交的信息,主要用于处理客户端请求 <FORM action="tom.js ...

  8. 【Linux开发】Ubuntu图形界面切换与磁盘扩展分区

    Ubuntu14.04设置字符界面快捷键:ctrl-alt-f1 切换回图形界面:ctrl-alt-f7 为虚拟机拓展了30G的空间,挂在了/mnt/sda3这个目录下: 说明一下Ubuntu14.0 ...

  9. 【Qt开发】Qt中图像的显示与基本操作

    Qt可显示基本的图像类型,利用QImage.QPxmap类可以实现图像的显示,并且利用类中的方法可以实现图像的基本操作(缩放.旋转). 1. Qt可显示的图像类型 参考Qt的帮助文档,可支持的类型,即 ...

  10. Canvas入门08-绘制仪表盘

    需求 实现下图所示的仪表盘的绘制. 分析 我们先来将仪表盘进行图形拆分,并定义尺寸. 我们绘制的逻辑: 绘制中心圆 绘制环外圈圆 绘制环内圈圆 绘制刻度内圈圆 绘制刻度线 绘制刻度文字 绘制指针 定义 ...