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 ...
随机推荐
- Solr实现SQL的查询与统计--转载
原文地址:http://shiyanjun.cn/archives/78.html Cloudera公司已经推出了基于Hadoop平台的查询统计分析工具Impala,只要熟悉SQL,就可以熟练地使用I ...
- CGLib动态代理引起的空指针异常
一个同事将公司的开发框架基于最新的Spring.Tomcat.Java版本作了部分修改,拿来开发运行之后,发现一个奇怪的空指针异常. 还原一下当时的场景,代码大概如下,所有的Servlet继承自Bas ...
- QoS专题-第4期-QoS实现之限速
QoS实现之限速 通过前面几篇介绍,大家都知道了MQC是实现QoS的技术,优先级映射是实现QoS的前提条件.读完之后也许无法直观感觉到QoS是如何提升网络服务质量.今天小编给大家介绍限速,通过实验,可 ...
- (转)Linux GCC常用命令
1简介 2简单编译 2.1预处理 2.2编译为汇编代码(Compilation) 2.3汇编(Assembly) 2.4连接(Linking) 3多个程序文件的编译 4检错 5库文件连接 5.1编译成 ...
- 【BZOJ4802】欧拉函数(Pollard_rho)
[BZOJ4802]欧拉函数(Pollard_rho) 题面 BZOJ 题解 这么大的范围肯定不好杜教筛. 考虑欧拉函数的计算式,显然只需要把\(n\)分解就好了. 直接\(Pollard\_rho\ ...
- 【BZOJ4828】【HNOI2017】大佬(动态规划)
[BZOJ4828][HNOI2017]大佬(动态规划) 题面 BZOJ 洛谷 LOJ 人们总是难免会碰到大佬.他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场 就能让周围 ...
- Unity3D for VR 学习(4): 自绘摄像机的视口区域锥体
在Unity Editor下,当选择Camera组件后,可呈现出Camera视口区域锥体,非常方便.但是当选择其他物体,如Cube后,就无法得知是否在Camera市口区内了,这里我找到了雨松MOMO的 ...
- 【OpenCV】特征检测器 FeatureDetector
<SIFT原理与源码分析>系列文章索引:http://www.cnblogs.com/tianyalu/p/5467813.html OpenCV提供FeatureDetector实现特征 ...
- 使用 css 的 keyframe 实现 loading 动画
效果查看:https://jsfiddle.net/rubys/je16qL5k/6/ <!DOCTYPE html> <html lang="en"> & ...
- [DeeplearningAI笔记]序列模型2.9情感分类
5.2自然语言处理 觉得有用的话,欢迎一起讨论相互学习~Follow Me 2.9 Sentiment classification 情感分类 情感分类任务简单来说是看一段文本,然后分辨这个人是否喜欢 ...