NOIP模拟赛 城市
题目描述
$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模拟赛 城市的更多相关文章
- NOIP模拟赛20161022
NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...
- contesthunter暑假NOIP模拟赛第一场题解
contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...
- NOIP模拟赛 by hzwer
2015年10月04日NOIP模拟赛 by hzwer (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...
- 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程
数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...
- 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...
- 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...
- 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1
题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...
- CH Round #58 - OrzCC杯noip模拟赛day2
A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...
- CH Round #52 - Thinking Bear #1 (NOIP模拟赛)
A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...
随机推荐
- C++解析(20):智能指针与类型转换函数
0.目录 1.智能指针 2.转换构造函数 3.类型转换函数 4.小结 1.智能指针 内存泄漏(臭名昭著的Bug): 动态申请堆空间,用完后不归还 C++语言中没有垃圾回收机制 指针无法控制所指堆空间的 ...
- QoS专题-第5期-QoS实现之队列调度与报文丢弃
QoS实现之队列调度与报文丢弃 前面的专题里面介绍了通过优先级映射或者MQC对报文进行分类和标记,那么分类之后要做什么呢?那就是根据分类结果对报文进行流量控制处理.拥塞管理和拥塞避免就是两种流量控制手 ...
- JS中数组和字符串具有的方法,以及substring,substr和slice的用法与区别
String 对象属性 属性 描述 constructor 对创建该对象的函数的引用 length 字符串的长度 prototype 允许您向对象添加属性和方法 String 对象方法 方法 描述 ...
- mysql数据库的存储过程
一. 什么是存储过程: 存储过程是一组可编程的函数,是为了完成特定功能的SQL语句集,经过第一次编译后再次调用不需要再次编译,创建并保存在数据库中,用户可通过指定存储过程的名字并给定参数(需要时)来调 ...
- 【Luogu1912】【NOI2009】诗人小G(动态规划)
[Luogu1912][NOI2009]诗人小G(动态规划) 题面 洛谷 题解 原来\(NOI\)这么多神仙题... 考虑一个极其明显的\(dp\) 设\(f[i]\)表示前\(i\)个句子产生的最小 ...
- 浴谷八连测R4题解
一开始出了点bug能看见排行榜,于是我看见我半个小时就A掉了前两题,信心场QAQ T1字符串题就不说了qwq #include<iostream> #include<cstring& ...
- 二次封装bootstrap-table及功能优化
/** * 设置bootstrat-table * @param params */ function setBootstrapTable (target, params) { // 默认设置表格内容 ...
- ctsc2009 移民站选址
分析:非常非常好的一道题! 首先需要对问题进行转化: 行列无关,对于行单独处理,对于列单独处理 必然存在一个最优方案使得每一个新站与旧站重合. 转化1很显然,对于转化2,是一类非常经典的“中位数问题” ...
- win32/linux 线程 log
原文 #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef WIN32 #includ ...
- Ajax-更新
ajax是与服务器进行(异步/同步)交互的技术之一交互就是对服务器一种访问ajax对服务器进行交互时页面不刷新ajax的语言载体是JS 比如我在百度输入个东西 自动弹出信息像和一些搜索字体相关的页面标 ...