这题好神啊……
正解方向是分治,据我所知的分治方法有:I.离线后直接对多边形以及所有的询问进行分治 II.建立多边形的分治结构(对于三角形来说类似线段树,对于对角线来说类似平衡树),然后每次在这个分治结构上进行查询 III.将原图转为其对偶图(利用拓扑),发现是一棵树,然后在这棵树上进行分治(似乎也有离线分治和在线建立分治结构两种方法)
我用的是第二种方法,感觉写起来不是很容易,但是也并不恶心,具体实现以及具体问题的处理方法见代码.
感觉这样分治的复杂度是log的,实际证明最坏情况下存在使得任意一侧的三角形数不少于n/3的分发,然而并不会证,大该感性理解一下吧.
思维笔记:I.分治无处不在 II.分治就是分治,也可以没有信息的合并 III.分治的出发点也可以是砍半,就像二分一样 IV.分治结构的建立类似分治,而分治结构的使用更像是二分
算法笔记:I.建立分治结构时所需信息,以及分治结构所需维护的信息,是不一样的,分开考虑与处理会方便得多 II.在分治结构中,储存信息的方式可以是对于每个点存储其在每一层的信息,也可以是对于每一层存储每个点的信息,两者各有千秋,在这道题里,个人感觉前者用起来更加方便 III.这道题分治的理由我感觉是——一个对角线把多边形切成两个部分,如果询问的两个点都在这两个部分里的其中一个里面,那这次询问一定与另一部分无关

#pragma GCC optimize("O3")
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define pb push_back
#define ft first
#define sd second
#define mmp(a,b) (std::make_pair(a,b))
char xB[(<<)+],*xS,*xT;
#define gtc (xS==xT&&(xT=((xS=xB)+fread(xB,1,1<<15,stdin)),xS==xT)?0:*xS++)
inline void read(int &x){
register char ch=gtc;
for(x=;ch<''||ch>'';ch=gtc);
for(;ch>=''&&ch<='';x=(x<<)+(x<<)+ch-'',ch=gtc);
}
typedef std::pair<int,int> pii;
typedef std::vector<int> vi;
typedef std::vector<pii> vii;
const int A=,N=,Inf=0x3f3f3f3f;
vi tmp1;
vii tmp2;
struct Block{
Block *ch[];
pii cut;
}*root,block[N<<];
#define newblock (block+(sz++))
int to[N][A],dis[N][A][];
int q[N],front,back,vis[N],id[N];
int n;
struct V{int to,next;}c[N<<];
int head[N],t;
inline void add(int x,int y){
c[++t].to=y,c[t].next=head[x],head[x]=t;
c[++t].to=x,c[t].next=head[y],head[y]=t;
}
int sz,cnt;
inline void bfs(int S,int deep,int opt){
++cnt,front=back=,q[back++]=S;
dis[S][deep][opt]=,vis[S]=cnt;
register int x,i;
while(front!=back){
x=q[front++];
for(i=head[x];i;i=c[i].next)
if(vis[c[i].to]!=cnt){
vis[c[i].to]=cnt;
dis[c[i].to][deep][opt]=dis[x][deep][opt]+;
q[back++]=c[i].to;
}
}
}
inline void build(Block *&p,register vi poi,register vii cut,int deep){
p=newblock;
if(cut.size()==)return;
pii mini;
int min=Inf,temp,size1=poi.size(),size2=cut.size();
register int i;
for(i=;i<size2;++i){
temp=std::abs(id[cut[i].ft]-id[cut[i].sd])+;
temp=std::max(temp,size1-temp+);
if(temp<min)
min=temp,mini=cut[i];
}
p->cut=mini;
int l=id[mini.ft],r=id[mini.sd];
if(l>r)std::swap(l,r);
tmp1.clear(),tmp2.clear();
for(i=;i<=l;++i){
tmp1.pb(poi[i]);
id[poi[i]]=tmp1.size()-;
to[poi[i]][deep]=;
}
for(i=r;i<size1;++i){
tmp1.pb(poi[i]);
id[poi[i]]=tmp1.size()-;
to[poi[i]][deep]=;
}
for(i=;i<size2;++i){
if(cut[i]==mini)continue;
if(to[cut[i].ft][deep]==&&to[cut[i].sd][deep]==)
tmp2.pb(cut[i]);
}
build(p->ch[],tmp1,tmp2,deep+);
tmp1.clear(),tmp2.clear();
for(i=l;i<=r;++i){
tmp1.pb(poi[i]);
id[poi[i]]=i-l;
to[poi[i]][deep]=;
}
for(i=;i<size2;++i){
if(cut[i]==mini)continue;
if(to[cut[i].ft][deep]==&&to[cut[i].sd][deep]==)
tmp2.pb(cut[i]);
}
build(p->ch[],tmp1,tmp2,deep+);
for(i=;i<size1;++i)head[poi[i]]=;
t=;
for(i=;i<size1;++i)
add(poi[i],poi[i-]);
add(poi[size1-],poi[]);
for(i=;i<size2;++i)
add(cut[i].ft,cut[i].sd);
bfs(mini.ft,deep,);
bfs(mini.sd,deep,);
}
inline int query(Block *p,int x,int y,int deep){
if(!p->ch[])return ;
if(p->cut.ft==x)return dis[y][deep][];
if(p->cut.sd==x)return dis[y][deep][];
if(p->cut.ft==y)return dis[x][deep][];
if(p->cut.sd==y)return dis[x][deep][];
if(to[x][deep]==to[y][deep])return query(p->ch[to[x][deep]],x,y,deep+);
int ret=dis[x][deep][]+dis[y][deep][];
ret=std::min(ret,dis[x][deep][]+dis[y][deep][]);
return ret;
}
int main(){
read(n);
register int i;pii rio;
for(i=;i<=n;++i)
tmp1.pb(i),id[i]=i-;
for(i=;i<=n-;++i)
read(rio.ft),read(rio.sd),tmp2.pb(rio);
build(root,tmp1,tmp2,);
int T,x,y;
read(T);
while(T--){
read(x),read(y);
printf("%d\n",x==y?:query(root,x,y,));
}
return ;
}

【BZOJ 4449】[Neerc2015]Distance on Triangulation 多边形分治结构的更多相关文章

  1. bzoj 4449: [Neerc2015]Distance on Triangulation

    Description 给定一个凸n边形,以及它的三角剖分.再给定q个询问,每个询问是一对凸多边行上的顶点(a,b),问点a最少经过多少条边(可以是多边形上的边,也可以是剖分上的边)可以到达点b. I ...

  2. 【bzoj 4449】[Neerc2015]Distance on Triangulation

    Description 给定一个凸n边形,以及它的三角剖分.再给定q个询问,每个询问是一对凸多边行上的顶点(a,b),问点a最少经过多少条边(可以是多边形上的边,也可以是剖分上的边)可以到达点b. I ...

  3. BZOJ4449 : [Neerc2015]Distance on Triangulation

    首先拓扑,每次取出度数为$2$的点,这样可以把所有三角形都找到. 那么建出对偶图,会发现是一棵树. 对这棵树进行点分治,每次取出重心,DFS求出所有在里面的点,然后从重心$3$个点分别做一次BFS. ...

  4. BZOJ 4012 HNOI2015 开店 树的边分治+分治树

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4012 题意概述:给出一颗N点的树,保证树上所有点的度不超过3,树上每个点有权值,每条边有权 ...

  5. POJ 1987 BZOJ 3365 Distance Statistics 树的分治(点分治)

    题目大意:(同poj1741,刷一赠一系列) CODE: #include <cstdio> #include <cstring> #include <iostream& ...

  6. BZOJ.4738.[清华集训2016]汽水(点分治 分数规划)

    BZOJ UOJ 记\(val_i\)是每条边的边权,\(s\)是边权和,\(t\)是经过边数,\(k\)是给定的\(k\). 在点分治的时候二分答案\(x\),设\(|\frac st-k|=x\) ...

  7. NOI 2007 货币兑换Cash (bzoj 1492) - 斜率优化 - 动态规划 - CDQ分治

    Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个 ...

  8. CodeChef - PRIMEDST Prime Distance On Tree 树分治 + FFT

    Prime Distance On Tree Problem description. You are given a tree. If we select 2 distinct nodes unif ...

  9. bzoj 3784: 树上的路径【点分治+st表+堆】

    参考:https://www.cnblogs.com/CQzhangyu/p/7071477.html 神奇的点分治序(或者叫点剖?).就是把点分治扫过的点依次放进队列里,然后发现,对于每一棵树摊到序 ...

随机推荐

  1. Phaser3让超级玛丽实现轻跳、高跳及加上对应的跳跃声音

      mario jumper 在线测试地址:http://www.ifiero.com/uploads/phaserjs3/jumper/ 空格键:轻按:跳低 ,长按:跳高键盘:--> 向右 , ...

  2. 53. [LeetCode] Maximum Subarray

    Given an integer array nums, find the contiguous subarray (containing at least one number) which has ...

  3. 剑指 Offer——数字在排序数组中出现的次数

    1. 题目 2. 解答 时间复杂度为 \(O(n)\) 的算法,顺序遍历数组,当该数字第一次出现时开始记录次数. class Solution { public: int GetNumberOfK(v ...

  4. Adobe InDesign CS6自学入门到高级视频教程

    关键字:Adobe InDesign 视频教程 点击获取视频教程 教程目录 第1章/1.卸载InDesign CS6.avi 第1章/2.安装InDesign CS6.avi 第2章/1.创建并编辑自 ...

  5. 分布式数据库中间件Mycat百亿级数据存储(转)

    此文转自: https://www.jianshu.com/p/9f1347ef75dd 2013年阿里的Cobar在社区使用过程中发现存在一些比较严重的问题,如高并发下的假死,心跳连接的故障,只实现 ...

  6. “Hello World!“”团队第五周召开的第二次会议

    今天是我们团队“Hello World!”团队第五周召开的第二次会议.也祝大家双十一快乐~~博客内容: 一.会议时间 二.会议地点 三.会议成员 四.会议内容 五.todo list 六.会议照片 七 ...

  7. 【探路者】互评beta版本

    成员博客 1蔺依铭:http://www.cnblogs.com/linym762/ 2张恩聚:http://www.cnblogs.com/zej87/ 3米赫:http://www.cnblogs ...

  8. 【java】中缀表达式转后缀表达式 java实现

    算法: 中缀表达式转后缀表达式的方法:1.遇到操作数:直接输出(添加到后缀表达式中)2.栈为空时,遇到运算符,直接入栈3.遇到左括号:将其入栈4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出 ...

  9. ARP 攻击

    场景 A攻击者 192.168.1.3 00:00:00:00:00:01 B受害者 192.168.1.2 00:00:00:00:00:02 C路由器 192.168.1.1 00:00:00:0 ...

  10. 【BioCode】根据seq与位点信息截取窗口

    代码说明 sequence24371.txt 以上为所有氨基酸的编号,序列,与位点标记.根据标记为“1”的位点,截取窗口:如下(实验结果): 图示为一个窗口为12的蛋白质片段 2N+1=25: 实现代 ...