热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

ZJOI2007捉迷藏:动态点分治的应用

Jiajia和Wind是一对幸福的家庭,拥有多名子女。某日,家庭成员们决定在家中的大型且结构复杂的住宅内玩捉迷藏游戏。该住宅由N个房间和N-1条双向走廊构成,确保任何两个房间间皆可互通。游戏过程中,孩子们会选择未开启灯光的房间作为藏身之处,而Jiajia则需寻找他们。Wind负责控制房间内的灯光,通过开关灯来调整游戏的难度。
### 题目背景
Jiajia 和 Wind 是一对幸福的家庭,他们育有多名子女。某天,全家决定利用家中独特的建筑布局——由 N 个房间和 N-1 条双向走廊组成的空间,进行一场别开生面的捉迷藏游戏。每个房间均可通过走廊与其他房间连通。

### 游戏规则
- 孩子们选择未开灯的房间藏匿。
- Wind 可以根据孩子们的要求随意开关灯光,增加游戏的趣味性和挑战性。
- Jiajia 的任务是在每次游戏开始时,计算出最远的两个未开灯房间之间的距离,以此评估游戏的难度。

### 输入输出格式
- **输入**:首先输入一个整数 N 表示房间数量,随后 N-1 行描述每条走廊连接的两个房间。最后一行输入一个整数 Q 表示操作次数,之后 Q 行分别给出具体的操作指令,包括改变房间的照明状态(C i)或开始一次游戏(G)。
- **输出**:对于每个 G 操作,输出一行非负整数表示最远的两个未开灯房间的距离。如果只有一个房间的灯是关着的,输出 0;如果所有房间的灯都是开着的,输出 -1。

### 解题思路
此问题可通过构建括号序列的方法解决。通过深度优先搜索(DFS),在访问每个节点时加入左括号,在回溯时加入右括号,从而形成一个代表树结构的括号序列。利用这一序列,可以方便地计算任意两点间的距离。

### 算法实现
1. **括号序列的构建**:使用 DFS 遍历树,记录每个节点的进入和离开时间,形成括号序列。
2. **距离计算**:通过分析括号序列中特定子序列的括号数量,计算两点间的距离。
3. **数据结构的选择**:采用线段树来高效地处理区间更新和查询操作,确保算法的时间复杂度满足题目要求。

### 代码实现
```cpp
#include
#define lc (hao<<1)
#define rc (hao<<1|1)
#define inf 214748364
#define N 100010
using namespace std;

struct Data {
int a, b, l1, l2, r1, r2, sum;
} tree[N<<4];

int to[N<<1], nxt[N<<1], head[N], st[N<<2], nct, cnt, tot, val[N], n, m, x, y;
bool is[N];
char op[2];

void addEdge(int x, int y) {
to[++nct] = y;
nxt[nct] = head[x];
head[x] = nct;
}

void dfs(int u, int fa) {
st[++cnt] = -1;
st[++cnt] = u;
val[u] = cnt;
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
if (v != fa) dfs(v, u);
}
st[++cnt] = -2;
}

void updateNode(int hao) {
if (tree[lc].b > tree[rc].a) {
tree[hao].a = tree[lc].a;
tree[hao].b = tree[lc].b - tree[rc].a + tree[rc].b;
} else {
tree[hao].b = tree[rc].b;
tree[hao].a = tree[rc].a - tree[lc].b + tree[lc].a;
}
tree[hao].l1 = max(tree[lc].l1, max(tree[rc].l1 + tree[lc].a - tree[lc].b, tree[rc].l2 + tree[lc].a + tree[lc].b));
tree[hao].l2 = max(tree[lc].l2, tree[rc].l2 - tree[lc].a + tree[lc].b);
tree[hao].r1 = max(tree[rc].r1, max(tree[lc].r1 - tree[rc].a + tree[rc].b, tree[lc].r2 + tree[rc].a + tree[rc].b));
tree[hao].r2 = max(tree[rc].r2, tree[lc].r2 + tree[rc].a - tree[rc].b);
tree[hao].sum = max(max(tree[lc].sum, tree[rc].sum), max(tree[lc].r1 + tree[rc].l2, tree[lc].r2 + tree[rc].l1));
}

void change(int hao, int x) {
tree[hao].a = tree[hao].b = 0;
tree[hao].l1 = tree[hao].r1 = tree[hao].l2 = tree[hao].r2 = tree[hao].sum = -inf;
if (st[x] == -1) tree[hao].b = 1;
else if (st[x] == -2) tree[hao].a = 1;
else if (!is[st[x]]) {
tree[hao].l1 = tree[hao].r1 = tree[hao].l2 = tree[hao].r2 = 0;
}
}

void buildTree(int hao, int l, int r) {
if (l == r) {
change(hao, l);
return;
}
int mid = (l + r) >> 1;
buildTree(lc, l, mid);
buildTree(rc, mid + 1, r);
updateNode(hao);
}

void updateTree(int hao, int l, int r, int x) {
if (l == r) {
change(hao, l);
return;
}
int mid = (l + r) >> 1;
if (x <= mid) updateTree(lc, l, mid, x);
else updateTree(rc, mid + 1, r, x);
updateNode(hao);
}

int main() {
scanf("%d", &n);
for (int i = 1; i scanf("%d%d", &x, &y);
addEdge(x, y);
addEdge(y, x);
}
dfs(1, -1);
tot = n;
buildTree(1, 1, cnt);
scanf("%d", &m);
while (m--) {
scanf("%s", op);
if (op[0] == 'G') {
if (tot == 1) puts("0");
else if (tot == 0) puts("-1");
else printf("%d\n", tree[1].sum);
} else {
scanf("%d", &x);
if (is[x]) {
tot++;
is[x] = 0;
} else {
tot--;
is[x] = 1;
}
updateTree(1, 1, cnt, val[x]);
}
}
return 0;
}
```
### 总结
通过构建括号序列并结合线段树的数据结构,本题提供了一个高效解决动态点分治问题的方法。这种方法不仅能够快速响应各种操作,还能准确计算出游戏中最远的两个未开灯房间的距离,为玩家提供了丰富的游戏体验。
推荐阅读
  • NFC OMA 接口访问优化
    本文探讨了NFC设备中OMA接口的访问方式,特别是针对IC制造商提供的NFC swp-sim访问与NFC服务提供商对eSe(嵌入式安全元件)访问的不同处理方法。文中提出了几种解决方案以解决由此产生的双SmartcardService运行问题。 ... [详细]
  • 深入理解Java NIO:基础概念与原理
    本文介绍了Java NIO(New Input/Output)的基本概念,包括同步与异步、阻塞与非阻塞等核心理念,以及NIO相对于传统IO的优势和应用场景。通过详细解析这些概念,帮助读者更好地理解和掌握NIO的使用。 ... [详细]
  • 本问题涉及对一个非负整数数组执行加一操作。数组以最高位数字在前的方式存储,每个数组元素仅包含一位数字。假设该整数没有前导零,除非该整数为0。 ... [详细]
  • 本文详细介绍了 Freemarker 模板引擎中的 include 指令,以及如何利用该指令从其他文件中引入内容,以增强页面的模块化和可维护性。 ... [详细]
  • 深入理解Kafka架构
    本文将详细介绍Kafka的内部工作机制,包括其工作流程、文件存储机制、生产者与消费者的具体实现,以及如何通过高效读写技术和Zookeeper支持来确保系统的高性能和稳定性。 ... [详细]
  • 本文详细介绍了ejabberd中的验证码服务、接收器以及服务器间通信的监督者和工作进程,包括它们的启动方式和主要功能。 ... [详细]
  • 在Ubuntu 16.04中使用Anaconda安装TensorFlow
    本文详细介绍了如何在Ubuntu 16.04系统上通过Anaconda环境管理工具安装TensorFlow。首先,需要下载并安装Anaconda,然后配置环境变量以确保系统能够识别Anaconda命令。接着,创建一个特定的Python环境用于安装TensorFlow,并通过指定的镜像源加速安装过程。最后,通过一个简单的线性回归示例验证TensorFlow的安装是否成功。 ... [详细]
  • 本文介绍了ThinkPHP框架的基本概念及其主要特性。作为一款遵循Apache许可证的开源框架,ThinkPHP不仅支持多种平台和Web服务器,还提供了丰富的功能以适应不同的开发需求。 ... [详细]
  • 列表是 Python 编程语言中最常用的数据结构之一,它类似于其他编程语言中的数组。本文将详细介绍 Python 3 中列表的基本操作和特性。 ... [详细]
  • 本文介绍了如何使用 useradd 命令来创建用户及其相关组,以及如何通过指定参数来定制用户的属性,如UID、GID、家目录等。同时,也探讨了使用 userdel 命令安全地删除用户及其所有相关文件的方法。 ... [详细]
  • 本文探讨了如何在Java后端配置CORS以支持或禁止携带凭证(如Cookie),并提供了前后端的具体实现方法。 ... [详细]
  • 深入探讨PHP中的输出缓冲技术(Output Buffering)
    本文深入解析了PHP中输出缓冲(Output Buffering)的原理及其在Web开发中的应用,特别是如何通过输出缓冲技术有效管理HTTP头部信息,提高代码的灵活性与健壮性。 ... [详细]
  • 本文详细介绍了如何在UniApp中集成H5微信公众号支付功能,包括前置条件、API调用方法及具体实现步骤。 ... [详细]
  • .NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了
    .NETCore中的一个接口多种实现的依赖注入与动态选择看这篇就够了最近有个需求就是一个抽象仓储层接口方法需要SqlServer以及Oracle两种实现方式,为了灵活我在依赖注入的 ... [详细]
  • 本文介绍如何利用QFileSystemModel进行目录的浏览、创建及删除操作,并提供了一个简单的对话框界面实现。 ... [详细]
author-avatar
A丶Iice-fjl
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有