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 ...
随机推荐
- [Code Festival 2017 qual A] C: Palindromic Matrix
题意 给出一个小写字母组成的字符矩阵,问能否通过重排其中的字符使得每行每列都是回文串. 分析 简化版:给出一个字符串,问能否通过重排其中的字符使得它是回文串.那么如果字符串长度为偶数,就需要a到z的个 ...
- Oracle中三种循环(For、While、Loop)案例
1.ORACLE中的FOR循环用法(九九乘法表) declare i ; j ; begin .. loop ..i loop Dbms_Output.put(i||'*'||j||'='||i*j) ...
- Contest 1
A:注意到模数是要求lcm的数的倍数,直接先取模就可以了.考场脑抽,对其质因数分解判了一下每个因子有没有,当然也行. #include<iostream> #include<cstd ...
- Spring Boot系列教程十:Spring boot集成Sentinel Redis
前言 上一篇文章介绍了spring boot集成单点的redis,然而实际生产环境使用单点的redis风险很高,一旦宕机整个服务将无法使用,这篇文章介绍如何使用基于sentinel的redis高可用方 ...
- 【转】大数据分析(Big Data OLAP)引擎Dremel, Tenzing 以及Impala
引自:http://blog.csdn.net/xhanfriend/article/details/8434896 对于数据分析师来说,SQL是主要的语言. Hive为Hadoop提供了支持SQL运 ...
- Zend Hash table 详解--转
原文地址:http://www.phppan.com/2009/12/zend-hashtable/ 在PHP的Zend引擎中,有一个数据结构非常重要,它无处不在,是PHP数据存储的核心,各种常量.变 ...
- 埃及分数&&The Rotation Game&&骑士精神——IDA*
IDA*:非常好用的搜索,可以解决很多深度浅,但是规模大的搜索问题. 估价函数设计思路:观察一步最多能向答案靠近多少. 埃及分数 题目大意: 给出一个分数,由分子a 和分母b 构成,现在要你分解成一系 ...
- C/C++中如何计算程序运行的时间
一个程序的功能通常有很多种方法来实现,怎么样的程序才算得上最优呢?举个例子,如果实现同一个功能的两个程序,一个一点按钮就给出运行结果,而另一个则需要漫长的时间去等待,就像安装WINDOWS XP一样( ...
- 很好的c++和Python混合编程文章
c++中嵌入python入门1 本人是用vc2003+python2.5学习的,其它的也应该差不了多少 0. 坏境设置把Python的include/libs目录分别加到vc的include/lib ...
- [linux]linuxI/O测试的方法之dd
参考http://www.thomas-krenn.com/en/wiki/Linux_I/O_Performance_Tests_using_dd Measuring Write Performan ...