题目:

A 国有 n 座城市,n−1 条双向道路将这些城市连接了起来,任何两个城市都可以通过道路互通。

某日,A 国爆发了丧尸危机,所有的幸存者现在都聚集到了 A 国的首都(首都是编号为 1 的城市)。而其它城市的丧尸会时不时地向首都发起进攻。

为了抵御丧尸的攻击,幸存者在 A 国的每座城市都修建了防御工事。编号为 i 的城市,其防御工事强度为 di。

当一只丧尸决定进攻首都时,它会从某城市 u(u≠1) 沿经过道路数量最少的路径前往首都。沿途,这只丧尸会试图突破当地的防御工事。

对于某座防御工事,如果丧尸的凶猛值不小于该防御工事的强度,丧尸就会突破这座防御工事,否则丧尸会被阻截在此。

注意:如果丧尸突破了某城市的防御工事,并代表此防御工事被破坏。该防御工事在面对后面来的丧尸的时候还会保持原先的强度。

输入格式

第一行,包含一个正整数 n。

第二行包含 n 个正整数,第 i 个正整数表示编号为 i 的城市的防御工事的强度 d_i​。

接下来 n-1 行,每行有两个空格隔开的整数 u,v,表示编号为 u 的城市与编号为 v 的城市之间有一条双向道路。

接下一行,包含一个正整数 q,表示发生了 q 次丧尸进攻首都的事件。

接下来 q 行,每行两个整数 u,x,表示有一只凶猛值为 x 的丧尸从编号为 u 的城市出发,进攻首都。

输出格式

输出 q 行,按照输入给出的顺序输出每个丧尸分别被阻截在了哪座城市。如果丧尸突破了所有的防御工事,攻入了首都,则请输出

The zombie ate your brains!

数据范围

本题包含 10 个测试点

对于前三个测试点,保证 n≤100

对于第四个到第六个测试点,保证第 i 条边连接了城市 i 和城市 i+1

对于全部测试点,保证 1≤n≤2×10^5,1≤di,x≤100,u≠1,1≤q≤2×10^5

输出时每行末尾的多余空格,不影响答案正确性

要求使用「文件输入输出」的方式解题,输入文件为 defend.in,输出文件为 defend.out

Sample Input

5
8 2 7 1 4
1 2
1 3
3 4
3 5
5
2 1
2 9
3 6
4 5
5 7

Sample Output

2
The zombie ate your brains!
3
3
1

题解:

很容易发现该题是最短路径问题,而且的记录路径的最短路径问题。

根据 题目我们有两种思路,第一个是对每个询问单独处理求点到点的最短路在寻路过程中计算结果,第二种是先对图进行处理求出点到所有点的最短路。

第一种方法,求两点之间最短距离的比较稳定的算法是Dijkstra算法,复杂度是O(m*logn).而后有q个查询复杂度应该是O(q*m*logn),q,m,n最大值都为2e5,明显会超时,由于这题图的特殊性,它是一个无权图,就是说边的权值默认是1,其实还可以用bfs和dfs求两点最短路,但时间复杂度也不理想因为拥有q个询问,就算复杂度为线性还是会超时。

第二种方法是,先预处理,求点到其他点的最短路径算法还是是Dijkstra算法,这个算法是以bfs为基础改进而来的,同样因为这题图的特殊性,用bfs就可以计算出点到其他点的最短路,然后最大的问题是如何储存路径,如果之间按点来储存所有路径,那在最坏情况(图为链状,比如 图是 1-2-3-4,对点储存就是:2:2-1,3:3-2-1,4:4-3-2-1。)空间复杂度会达到n^2级别,很有可能超内存,同时数据复制带来的的时间复杂度也会提高。从刚刚的链状图的路径储存,我们会发现有很多重复的部分,就利用他来压缩路径。

构造一个数组path[i]=j,其中i指第i个点的最短路的最后一个路径是i-j。用这种方法就可以将最短路路径完美的储存在数组里面。

                               |0,1,2,3,4,5,6|

用它获得路径的方法也很简单,比如我们有这样子的数组path[]={0,0,1,2,2,6,1},我们要获得从5到1的路径,path[5]=6,path[6]=1,说明5到1的路径是5-6-1,同样,我们要获得3到1的路径,path[3]=2,path[2]=1,所以3到1的路径是,3-2-1。

加入一个新的点也很简单,只要找到这个点的最短路的最后一步直接加在数组后面就可以,这也正好符合了bfs搜索的方法。

因为这题卡时间复杂度比较厉害,所以再提供3个优化思路。

一 链式向前星存边:

储存图不要使用常用的方便的vector<int>e[n],因为vector的分配内存和改变迭代器很消耗时间。所以使用链式向前星来储存,会很大程度的优化时间复杂度,一定程度的优化空间复杂度。

链式向前星和前文中储存路径的方法有些许类似,实际上链式向前星是一种数组模拟单向链表的操作。

一般的链式向前星的主体是3个数组加一个整数,head[],to[],next[],k(一般会写成结构体,如果有权值可在加入一个数组储存权值),

head[i]=j,指点i的边的最后一个索引是j  to[i]=j,指索引i指向的点是j  next[i]=j,指索引i的下一个索引是j,k指边的个数.

使用前先对索引初始化,将所有索引置为-1,即将head,next置为-1;

加入新边的操作是给予新边一个索引(就是k),将新边的目标点存入相应的to数组里面,将相应的next更新为head的值,然后将head的值更新为这个新边的索引。

遍历结构体的方法与之前的路径遍历方法类似。

包装的结构体

struct Edge {
int to, next;
};
struct  CStar {

    Edge edge[];
int head[];
int k;
CStar() {
k = ;
for (int i = ; i < ; i++) {
head[i] = -;
edge[i].next = -;
}
}
void push(int a, int b) {
edge[k].to = b;
edge[k].next = head[a];
head[a] = k++;
}
};

遍历边的操作

for (int i = e.head[x]; ~i; i = e.edge[i].next)
...

二 路径最大值:

在每一个查询中遍历路径进行计算也有挺高的复杂度,特别是在僵尸凶猛值很大时,这样它就要遍历一整条路径。我们可以用一些方法来避免出现遍历整条路径的情况,我们可以在计算最短路径时顺势算出最短路径中的最大防御值,并储存在数组中。这样我们最后进行查询时如果僵尸凶猛值大于等于这个路径防御最大值就可以直接输出“The zombie ate your brains!”

三 路径优化:

这个方法理论上可以一定程度减少复杂度,但我个人在本题样例上使用的并不那么有效,但也提出了作为一个思路扩展。

这个思路是基于当你大于等于一个值x后就肯定大于等于一个小于等于x的值。

所以我们可以以此思路对路径进行优化,使路径的每一条路变得严格递增,从而优化查询时间。

例子:

可以变化成

可以在不改变结果的情况下降低树的深度,从而降低查询时间。

用文字描述过程就是,将一个点连到它最短路上第一个大于等于它值的数上,直到它达到首都(也就是编号为1的点)

AC代码:

#include<iostream>
#include<queue>
#include<algorithm>
#include<cctype> using namespace std; struct Edge {
int to, next;
}; struct CStar { Edge edge[];
int head[];
int k;
CStar() {
k = ;
for (int i = ; i < ; i++) {
head[i] = -;
edge[i].next = -;
}
}
void push(int a, int b) {
edge[k].to = b;
edge[k].next = head[a];
head[a] = k++;
}
}; CStar e; int d[];
int path[];
int book[];
int ld[];
queue<int>qu; int main() {
#if 1
freopen("defend.in", "r", stdin);
freopen("defend.out", "w", stdout);
#endif int n, q, a, b;
int x, u, flag, len, it;
scanf("%d", &n); for (int i = ; i <= n; ++i) {
scanf("%d", d + i);
} for (int i = ; i < n; ++i) {
scanf("%d%d", &a, &b);
e.push(a, b);
e.push(b, a);
} qu.push();
book[] = ;
path[] = ;
ld[] = d[];
while (!qu.empty()) {
x = qu.front(); for (int i = e.head[x]; ~i; i = e.edge[i].next) {
it = e.edge[i].to;
if (book[it] == ) {
book[it] = ;
path[it] = x;
ld[it] = max(ld[x], d[it]);
qu.push(it);
}
}
qu.pop(); } scanf("%d", &q);
while (q--) {
flag = ;
scanf("%d%d", &u, &x);
if (ld[u] <= x)printf("The zombie ate your brains!\n");
else {
while (u) {
if (x < d[u]) {
flag = ;
printf("%d\n", u);
break;
}
u = path[u];
}
if (flag)printf("The zombie ate your brains!\n");
}
} return ;
}

【bfs+链式向前星】防御僵尸(defend)计蒜客 - 45288的更多相关文章

  1. 图论 ---- spfa + 链式向前星 ---- poj 3268 : Silver Cow Party

    Silver Cow Party Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 12674   Accepted: 5651 ...

  2. Tarjan模版(链式向前星表示方法)

    这道模版用到了链式向前星表示法: struct node { int v,next; }edge[]; void add(int x,int y) { edge[++cnt].next=heads[x ...

  3. 【数据结构】链式向前星知识点&代码

    代码: struct NODE{ int to; int nxt; int c; }node[MM];//链式向前星 ; void add(int a,int b,int c){ node[lcnt] ...

  4. 图论 --- spfa + 链式向前星 : 判断是否存在正权回路 poj 1860 : Currency Exchange

    Currency Exchange Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 19881   Accepted: 711 ...

  5. 图论 --- spfa + 链式向前星 (模板题) dlut 1218 : 奇奇与变形金刚

    1218: 奇奇与变形金刚 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 130  Solved: 37[Submit][Status][Web Boa ...

  6. 计蒜客 39272.Tree-树链剖分(点权)+带修改区间异或和 (The 2019 ACM-ICPC China Shannxi Provincial Programming Contest E.) 2019ICPC西安邀请赛现场赛重现赛

    Tree Ming and Hong are playing a simple game called nim game. They have nn piles of stones numbered  ...

  7. 计蒜客 一维坐标的移动(BFS)

    在一个长度为 n 的坐标轴上,蒜头君想从 A 点 移动到 B 点.他的移动规则如下: 向前一步,坐标增加 1. 向后一步,坐标减少 1. 跳跃一步,使得坐标乘 2. 蒜头君不能移动到坐标小于 0 或大 ...

  8. 计蒜客模拟赛D2T3 蒜头君救人:用bfs转移状压dp

    题目链接:https://nanti.jisuanke.com/t/16444 题意: 蒜头君是一个乐于助人的好孩子,这天他所在的乡村发生了洪水,有多名村民被困于孤岛上,于是蒜头君决定去背他们离开困境 ...

  9. 计蒜客 无脑博士 bfs

    题目链接无脑博士的试管们 思路:直接模拟倒水过程即可,但是需要记忆判断当前的情况是否已经处理过.dfs和bfs都ok AC代码 #include <cstdio> #include < ...

随机推荐

  1. 十万同时在线用户,需要多少内存?——Newbe.Claptrap 框架水平扩展实验

    Newbe.Claptrap 项目是笔者正在构建以反应式.Actor模式和事件溯源为理论基础的一套服务端开发框架.本篇我们将来了解一下框架在水平扩展方面的能力. 前情提要 时隔许久,今日我们再次见面. ...

  2. 3、尚硅谷_SSM高级整合_使用ajax操作实现删除的功能

    点击删除的时候,要删除联系人,这里同点击编辑按钮一样给删除按钮添加点击事件的时候不能使用 $(".delete_btn").click(function(){ }); 这种方式,因 ...

  3. 网络编程 套接字socket TCP UDP

    网络编程与套接字 网络编程 网络编程是什么: ​ 网络通常指的是计算机中的互联网,是由多台计算机通过网线或其他媒介相互链接组成的 ​ 编写基于网络的应用程序的过程序称之为网络编程. 网络编程最主要的工 ...

  4. python list遍历方法汇总

    list=['a','b','c','d','e'] #方法1: print('#方法1:') #i值为列表的item,list为列表名,因此i值即为列表元素 for i in list: #list ...

  5. layui动态添加的元素click等事件触发不了的解决办法

    在页面加载完成时候 '.add_project' 元素是可以触发click时间的,当动态添加 '.add_project' 时候,新添加的元素却触发不了click事件,类似下面的写法: $(" ...

  6. Syntax error, insert "}" to complete MethodBody

    jsp中代码在Eclipse中打开正常,导入项目导入MyEclipse后显示如下异常: Syntax error, insert "}" to complete MethodBod ...

  7. 一个神奇的SQL语句

    题目是这样的: 分别往这两张表中添加3条数据... 查询营业额最高商家的商品总价与营业额最低商家的商品总价差是多少(5分)CREATE VIEW vm2 AS SELECT price*limit_n ...

  8. 搭建一套ASP.NET Core+Nacos+Spring Cloud Gateway项目

    前言     伴随着随着微服务概念的不断盛行,与之对应的各种解决方案也层出不穷.这毕竟是一个信息大爆发的时代,各种编程语言大行其道,各有各的优势.但是有一点未曾改变,那就是他们服务的方式,工作的时候各 ...

  9. @Autowired 引发的一系列思考

    关于Java注解 注解定义 标记注解 - 没有元素 @interface Marker { } 单元素注解 - 只有一个元素 @interface Single { String value() de ...

  10. 智联家园-四大人工智能虚拟形象首秀MV

    2020 世界人工智能大会云端峰会在上海举行,由微软小冰作曲并携手其他 AI 演唱的 2020 世界人工智能大会云端峰会主题曲<智联家园> 今天正式发布,同时这也是小冰上海音乐学院毕业后的 ...