题目描述

$ZZQ$ 是一国之主。 这个国家有$N$个城市, 第$i$个城市与第$(i + 1) (mod N)$和$(i - 1) (mod N)$在一个正$N$边形相连。

$ZZQ$ 又新建了$N - 3$条道路。这些道路都是连接两个城市的直线 段,且任意两条线段都只可能在城市处相交,不会在旧的道路上新建 道路。同时$ZZQ$钦定任何一条新旧道路通行都只需要花费$1$天时间。

建设完成后,$ZZQ$开始了$M$次旅行,她想知道每次旅行最少需要 花费多少天。

输入输出格式

输入格式:

第一行输入 一个 个正整数$N$,表示城市个数。

接下来$N - 3$行,每行两个整数$u, v$,表示这条道路连接的两个城市。

接下来一个整数$M$,表示旅行次数。

接下来$M$行,每行两个整数$u, v$表示这次旅行的起点和终点。

保证起点和终点不同。

输出格式:

对于每个询问,输出一行一个整数$ans$表示答案。


其实这题在$BZOJ$上有原题:$BZOJ - 4449$

首先这显然是一个平面图,然后正解是平面图转对偶图 + 点分治,对偶图是什么?我不知道啊。

然后对偶图就是将平面图的面看作点,然后相邻的面之间连边,其中有$N - 3$条边,$N - 2$个点,故对偶图显然是一棵树。

其中,要建对偶图的话,每次选择$Deg$为$2$的点,再处理一下三角剖分,就能知道有哪些面相连了。

然后就在树上点分治。

至于过程,考虑一条原图的新加的边,如果某个询问的两个点恰好跨过它,那么就一遍$BFS$就好了,否则找到它们所在的被此时直线切割形成的两个块的左块或右块进行分治,于是可以使用点分治。

那么如何处理多个询问有哪几个横跨了当前点分治中心呢?只需将询问编号与当前分治中心用链式前向星连起来,访问到当前中心时扫一遍即可,当然这是需要下传的。

复杂度$O(NlogN)$。

代码:

 #pragma GCC optimize ("O3")
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm> using namespace std; const int MAXN = 1e05 + ;
const int MAXM = 1e05 + ;
const int MAXQ = 1e05 + ; const int INF = 0x7fffffff; struct LinkedForwardStar {
int to;
bool ban; int next;
} ; LinkedForwardStar Link[MAXM << ];
int Head[MAXN]= {};
int size = ; void Insert (int u, int v) {
Link[++ size].to = v;
Link[size].ban = false;
Link[size].next = Head[u]; Head[u] = size;
} vector<int> Graph[MAXN]; struct Edge {
int u, v;
int index; Edge () {} Edge (int fu, int fv, int find) :
u (fu), v (fv), index (find) {} bool operator < (const Edge& p) const {
if (u == p.u)
return v < p.v;
return u < p.u;
}
} ; Edge Edges[MAXN * ];
int edges = ;
int ind = ; int Triangle[MAXN][]; void AddEdge (int x, int y, int z) { // 处理三角剖分
ind ++;
Triangle[ind][] = x;
Triangle[ind][] = y;
Triangle[ind][] = z;
Edges[++ edges] = Edge (min (x, y), max (x, y), ind);
Edges[++ edges] = Edge (min (x, z), max (x, z), ind);
Edges[++ edges] = Edge (min (y, z), max (y, z), ind);
// cout << "Test: " << x << ' ' << y << ' ' << z << endl;
} int N, M; int Deg[MAXN]= {};
bool Vis[MAXN]= {false}; queue<int> Que; void Toposort () {
for (int i = ; i <= N; i ++)
if (Deg[i] == )
Que.push(i); while (! Que.empty()) {
int u = Que.front();
Que.pop(); if (Deg[u] != )
continue;
Vis[u] = true; int x = , y;
for (int i = ; i < (int) Graph[u].size(); i ++) {
int v = Graph[u][i];
if (Vis[v])
continue; ! x ? x = v : y = v;
Deg[v] --;
if (Deg[v] == )
Que.push(v);
}
AddEdge (u, x, y);
}
} void Construct () {
sort (Edges + , Edges + edges + );
for (int i = ; i < edges; i ++)
if (Edges[i].u == Edges[i + ].u && Edges[i].v == Edges[i + ].v) {
Insert (Edges[i].index, Edges[i + ].index);
Insert (Edges[i + ].index, Edges[i].index);
}
} int Size[MAXN]= {}; int tot; int minval = INF, gravity;
void Get_Gravity (int root, int father) {
Size[root] = ;
int maxpart = ;
for (int i = Head[root]; i; i = Link[i].next) {
int v = Link[i].to;
if (v == father || Link[i].ban)
continue; Get_Gravity (v, root);
Size[root] += Size[v];
maxpart = max (maxpart, Size[v]);
}
maxpart = max (maxpart, tot - Size[root]); if (maxpart < minval) {
minval = maxpart;
gravity = root;
}
} LinkedForwardStar Qlink[MAXQ << ];
int Qhead[MAXN];
int qsize = ; void Qinsert (int u, int v) {
Qlink[++ qsize].to = v;
Qlink[qsize].next = Qhead[u]; Qhead[u] = qsize;
} int Answer[MAXQ]= {}; int Dist[][MAXN]= {}; int cur = ; int Rec[MAXN * ];
int Belong[MAXN], Last[MAXN];
// Belong[]记录所属子树,Last[]记录分治中心编号(为了防止BFS越过当前分支中心管理子树) int cnt = ; void BFS (int S, int type) {
while (! Que.empty())
Que.pop();
for (int i = ; i <= cnt; i ++)
Dist[type][Rec[i]] = INF; Que.push(S);
Dist[type][S] = ; while (! Que.empty()) {
int u = Que.front();
Que.pop(); for (int i = ; i < (int) Graph[u].size(); i ++) {
int v = Graph[u][i];
if (Dist[type][v] < INF || Last[v] < cur)
continue; Dist[type][v] = Dist[type][u] + ;
Que.push(v);
}
}
} void DFS (int root, int father, int top) {
for (int j = ; j < ; j ++) {
Rec[++ cnt] = Triangle[root][j];
Belong[Triangle[root][j]] = top;
Last[Triangle[root][j]] = cur;
} for (int i = Head[root]; i; i = Link[i].next) {
int v = Link[i].to;
if (v == father || Link[i].ban)
continue;
DFS (v, root, top);
}
} pair<int, int> Queries[MAXQ]; int Query[MAXQ]; void Solve (int root) {
if (! Qhead[root])
return ; tot = Size[root];
minval = INF;
Get_Gravity (root, );
cur ++, cnt = ;
for (int i = Head[gravity]; i; i = Link[i].next) {
int v = Link[i].to;
if (Link[i].ban)
continue;
DFS (v, gravity, v);
}
for (int j = ; j < ; j ++) {
Rec[++ cnt] = Triangle[gravity][j];
Belong[Triangle[gravity][j]] = gravity;
Last[Triangle[gravity][j]] = cur;
} for (int j = ; j < ; j ++)
BFS (Triangle[gravity][j], j);
cnt = ;
for (int i = Qhead[root]; i; i = Qlink[i].next) {
int v = Qlink[i].to;
Query[++ cnt] = v;
}
Qhead[root] = ; for (int i = ; i <= cnt; i ++) {
int u = Queries[Query[i]].first, v = Queries[Query[i]].second;
if (Belong[u] == Belong[v]) {
if (Belong[u] == gravity)
Answer[Query[i]] = ; // 在同一个三角剖分中
else
Qinsert (Belong[u], Query[i]);
}
else {
for (int j = ; j < ; j ++)
Answer[Query[i]] = min (Answer[Query[i]], Dist[j][u] + Dist[j][v]);
}
} for (int i = Head[gravity]; i; i = Link[i].next) {
int v = Link[i].to;
if (! Link[i].ban) {
Link[i ^ ].ban = true;
Solve (v);
}
}
} int getnum () {
int num = ;
char ch = getchar (); while (! isdigit (ch))
ch = getchar ();
while (isdigit (ch))
num = (num << ) + (num << ) + ch - '', ch = getchar (); return num;
} int main () {
// freopen ("city.in", "r", stdin); N = getnum (); for (int i = ; i <= N; i ++)
Dist[][i] = Dist[][i] = Dist[][i] = INF; for (int i = ; i < N; i ++) {
Graph[i].push_back(i + );
Graph[i + ].push_back(i);
Deg[i] ++, Deg[i + ] ++;
}
Graph[].push_back(N), Graph[N].push_back();
Deg[] ++, Deg[N] ++;
for (int i = ; i <= N - ; i ++) {
int u, v;
u = getnum (), v = getnum ();
u ++, v ++;
Graph[u].push_back(v);
Graph[v].push_back(u);
Deg[u] ++, Deg[v] ++;
} Toposort ();
Construct (); M = getnum (); for (int i = ; i <= M; i ++) {
int u, v;
u = getnum (), v = getnum ();
u ++, v ++;
if (u != v) {
Queries[i] = make_pair (u, v);
Qinsert (, i); // 一开始所有询问都位于根节点的子树中
Answer[i] = INF;
}
} Size[] = N;
Solve (); for (int i = ; i <= M; i ++)
printf ("%d\n", Answer[i]); return ;
} /*
6
0 2
0 3
0 4
4
1 5
3 0
4 5
2 4
*/

NOIP模拟赛 城市的更多相关文章

  1. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  2. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  3. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  4. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

  5. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  6. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  7. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  8. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  9. CH Round #52 - Thinking Bear #1 (NOIP模拟赛)

    A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...

随机推荐

  1. [CF1111C]Creative Snap

    题目大意:有一个长度为$2^n(n\leqslant30)$的格子,有$k(k\leqslant10^5)$个球,分布在这些格子中,有两种消灭格子的方法: 1. 若一段格子长度大于等于$2$,可以对半 ...

  2. 利用Runloop优化流畅度

    我们可以对runloop添加观察者,当观察到状态为kCFRunLoopExit,kCFRunLoopBeforeWaiting的时候,做一些耗时的处理,废话不说,直接上代码 - (void)viewD ...

  3. elasticsearch 第一篇(入门篇)

    介绍 elasticsearch是一个高效的.可扩展的全文搜索引擎 基本概念 Near Realtime(NRT): es是一个接近实时查询平台,意味从存储一条数据到可以索引到数据时差很小,通常在1s ...

  4. 【BZOJ4828】【HNOI2017】大佬(动态规划)

    [BZOJ4828][HNOI2017]大佬(动态规划) 题面 BZOJ 洛谷 LOJ 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场 就能让周围 ...

  5. 监听input内容改变的oninput与onpropertychange在ie9的bug

    在做autocomplate的时候发现,ie9中,剪切.退格.删除不触发oninput事件,而ie9和ie9+已经移除了onpropertychange事件. 只好尝试添加退格.delete.剪切事件 ...

  6. python函数:字符串函数示例

    优先掌握的操作 #作用:名字,性别,国籍,地址等描述信息 #定义:在单引号\双引号\三引号内,由一串字符组成 name='egon' #优先掌握的操作: #1.按索引取值(正向取+反向取) :只能取 ...

  7. (转)ARC指南 - strong、weak指针

    一.简介 ARC是自iOS 5之后增加的新特性,完全消除了手动管理内存的烦琐,编译器会自动在适当的地方插入适当的retain.release.autorelease语句.你不再需要担心内存管理,因为编 ...

  8. tf.train.batch的偶尔乱序问题

    tf.train.batch的偶尔乱序问题 觉得有用的话,欢迎一起讨论相互学习~Follow Me tf.train.batch的偶尔乱序问题 我们在通过tf.Reader读取文件后,都需要用batc ...

  9. JavaScript之RegExp

    分为字面量和RegExp构造函数 1.正则表达式的匹配模式支持3个标志 g:表示全局模式,模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止 i:表示不区分大小写模式,即在确定匹配项时忽略模式 ...

  10. HTML入门(一)

    ---恢复内容开始--- HTML 一 .HTML介绍 1. 什么是HTML? 超文本标记语言: 超文本: 比普通文本更强大 标记语言: 使用一组标签对内容进行描述的一门语言,它不是编程语言! 2. ...