UVALive 6584 Escape (Regionals 2013 >> Europe - Central)
题目
给出一棵树,每个节点有一个怪物或血药,遇到怪物必须打,打完后扣掉一定的血量。
一开始英雄的血量为\(0\),当血量小于\(0\)时就挂了。
给出英雄的起点和终点,问能否成功到达终点。
算法
这题的方法真的是太美妙了!感觉ACM的题目比OI的好多了,因为它的程序不长,并且每题都不容易想啊。
我们先来解决一个弱化版问题:把起点作为根,问英雄最多能加多少血。
我们可以想象每个点有一个礼包,这个礼包有两个属性,不妨用\((a,b)\)表示,表示当英雄的血量不少于\(a\)时可以加上\(b\)点血量(\(b\)是负数就减血量)。但是有些限制,如果要取某个礼包,那么它的所有祖先上的礼包都必须先取。
我们现在尝试对每棵子树维护一些礼包,首先要保证所有的礼包都是奖励的。我们不妨假设现在对于点\(v\),要根据它的所有儿子\(u_i\)的礼包合成点\(v\)子树的礼包。对于点\(v\),如果它有怪物,我们就要想办法通过提高\(a\)使得\(b\)变为非负数(提高\(a\)是为了取子树的礼包),如果不行,那么这棵子树是不可能走进去的(因为走进去就一定扣血啊)。
通过提高\(a\)的值,现在我们成功地在点\(v\)已经生成了一个礼包,如此下去,我们对于根就生成了一棵礼包树,每个点都是有奖励的!我们就贪心(先选\(a\)最小的)往下走就好了,这个贪心的话,可以用一个左偏树来维护礼包。每开启一个礼包,就把这个礼包的儿子也加进去。
解决了这个弱化版问题后,剩下的就简单了。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long i64;
const int MAXN = (int) 2e5 + 3;
int n, target;
int A[MAXN];
struct Node{
Node* s[2];
int dis;
i64 minus, plus;
void init() {
s[0] = s[1] = NULL;
dis = 0;
minus = plus = 0;
}
};
Node node[MAXN];
struct Edge {
Edge* next;
int to;
};
Edge mem[MAXN * 2];
Edge* info[MAXN];
Edge* curMem;
void insert(int a, int b) {
curMem->to = b;
curMem->next = info[a];
info[a] = curMem ++;
}
Node* merge(Node* x, Node* y) {
if (! x) return y;
if (! y) return x;
if (x->minus > y->minus) swap(x, y);
x->s[1] = merge(x->s[1], y);
if (x->s[1] ? x->s[1]->dis : 0 > x->s[0] ? x->s[0]->dis : 0)
swap(x->s[0], x->s[1]);
x->dis = x->s[1] ? x->s[1]->dis + 1 : 1;
return x;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
#endif
scanf("%*d");
while (scanf("%d%d", &n, &target) == 2) {
curMem = mem;
memset(info, 0, sizeof info);
for (int i = 1; i <= n; i ++)
scanf("%d", A + i);
for (int i = 1; i < n; i ++) {
int v, u;
scanf("%d%d", &v, &u);
insert(v, u);
insert(u, v);
}
static int que[MAXN];
static int fa[MAXN];
memset(fa, 0, sizeof fa);
int low = 0, high = 0;
que[high ++] = target;
while (low < high) {
int v = que[low ++];
for (Edge* pt = info[v]; pt; pt = pt->next) {
int u = pt->to;
if (u != fa[v]) {
fa[u] = v;
que[high ++] = u;
}
}
}
static bool path[MAXN];
memset(path, 0, sizeof path);
for (int v = 1; v != 0; v = fa[v])
path[v] = true;
for (int i = high - 1; i > 0; i --) {
int v = que[i];
if (path[v]) continue;
Node* son = NULL;
for (Edge* pt = info[v]; pt; pt = pt->next)
if (! path[pt->to] && pt->to != fa[v])
son = merge(son, &node[pt->to]);
Node* cur = node + v;
cur->init();
cur->minus = max(0, - A[v]);
cur->plus = A[v];
while (son && (cur->plus < 0 || cur->minus > son->minus)) {
if (cur->plus < 0) {
cur->minus = max(cur->minus, son->minus - cur->plus);
cur->plus += son->plus;
}
else {
cur->plus += son->plus;
}
son = merge(son->s[0], son->s[1]);
}
cur = merge(cur, son);
if (cur->plus < 0) cur = NULL;
}
i64 hp = 0;
bool ok = true;
Node* tree = NULL;
for (int v = 1; v != 0; v = fa[v]) {
hp += A[v];
if (hp < 0) {
ok = false;
break;
}
for (Edge* pt = info[v]; pt; pt = pt->next) {
int u = pt->to;
if (path[u]) continue;
if (u == fa[v]) continue;
tree = merge(tree, &node[u]);
}
while (tree && hp >= tree->minus) {
hp += tree->plus;
tree = merge(tree->s[0], tree->s[1]);
}
}
if (ok) printf("escaped\n");
else printf("trapped\n");
}
return 0;
}
UVALive 6584 Escape (Regionals 2013 >> Europe - Central)的更多相关文章
- UVALive 6931 Can't stop playing (Regionals 2014 >> Europe - Central)
题目 一开始有一个双头队列,每次添加一个数(这是数是二的幂,所有数的和不大于\(2^13\)),由你来决定添加到队头还是队尾.如果队列里面相邻的两个数相同,设它们都是\(x\),那么这两个数会合并为\ ...
- Regionals 2013 :: North America - Southeast USA
Regionals 2013 :: North America - Southeast USA It Takes a Village As a Sociologist, you are studyin ...
- UVALive 5545 Glass Beads
Glass Beads Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Origin ...
- UVALive 2664 One-way traffic
One-way traffic Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Or ...
- UVALive 2957 Bring Them There
Bring Them There Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. O ...
- UVALive 3989 Ladies' Choice
Ladies' Choice Time Limit: 6000ms Memory Limit: 131072KB This problem will be judged on UVALive. Ori ...
- UVALive 5583 Dividing coins
Dividing coins Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Ori ...
- UVALive 5292 Critical Links
Critical Links Time Limit: 3000ms Memory Limit: 131072KB This problem will be judged on UVALive. Ori ...
- 世界GDP数据可视化
各国GDP数据可视化 数据来自世界银行 导入资源包,如下: Pandas, numpy, seaborn 和 matplotlib import pandas as pd import numpy a ...
随机推荐
- Java排序之排序大综合
一.最近写了一些排序,于是和和大家分享一下:(默认都是从小到大排序) 二.冒泡排序 1.什么是冒泡排序:原理是临近的两个数比较大小,将较大的数往后移,这样遍历一趟数组以后,最大的数就排在的最后面(时间 ...
- filter, sort
def is_odd(n): return n % 2 == 1 t = list(filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0])) print(t) # ...
- Quiz 6a Question 7————An Introduction to Interactive Programming in Python
First, complete the following class definition: class BankAccount: def __init__(self, initial_bal ...
- 基于百度地图api + AngularJS 的入门地图
转载请注明地址:http://www.cnblogs.com/enzozo/p/4368081.html 简介: 此入门地图为简易的“广州大学城”公交寻路地图,采用很少量的AngularJS进行inp ...
- Linux下Qt应用程序的发布(使用LDD命令查看所有依赖的库文件)
最近一直在学习Qt,用Qt写了一个程序,但是不知道怎么发布,网上说的都是在windows下怎么发布Qt应用程序,但是,在windows下Qt应用程序依赖的库文件与linux下的名字不同.于是,我就想到 ...
- 基于visual Studio2013解决C语言竞赛题之0302字符数出
题目 解决代码及点评 根据题目要求,只要根据用户输入的字母,判断字母之后,给出相应的输出即可 在以下代码中,f32函数实现了该功能,通过if条件判断语句 #include <stdio.h ...
- MYSQLI - mysqli操作数据库
<?php //模型类 class Model { //数据库连接 private $_conn = NULL; //where语句 private $_where = NULL; //表名称 ...
- postgresql文档生成注意事项
如果要生成中文版的postgresql,目前我所知道的方法见我的一篇博客http://www.cnblogs.com/codeblock/p/4812445.html 里面有详细的介绍,但是生成的文档 ...
- 【HTML相关】iframe+javascript实现一个表单提交后多个处理文件按序处理
最近在弄一个网页的问题,总结如下. [问题描述] 页面中包括以下几个部分:1)表单form,供用户输入图片文件:2)iframe1,显示a.php文件的内容,a.php接收客户端图片并保存,后台程序处 ...
- BZOJ 1798: [Ahoi2009]Seq 维护序列seq( 线段树 )
线段树.. 打个 mul , add 的标记就好了.. 这个速度好像还挺快的...( 相比我其他代码 = = ) 好像是#35.. ---------------------------------- ...