BZOJ4003 [JLOI2015]城池攻占

时间:2021-11-17 14:56:33

这题有两种做法来着。。。

第一种就是一开始想到的比较不靠谱,不过貌似可以过掉:

看从$1$号节点开始到$p$号节点最大需要的体力,记录单调上升的体力,询问的时候二分跳着走就可以了

不过精度问题还有可能爆double什么的QAQ

于是写了一半果断弃疗。。。结果有人说他过了【摔

第二种是正解,对于每个点我们可以先把下面的骑士都先做完然后还活着的全部搞到这个点上来,然后再看有谁死在这个点上了

所以我们要维护能都删除/查询最小值,合并,允许打标记的数据结构

貌似是可并堆喵!【完结撒花~

 /**************************************************************
Problem: 4003
User: rausen
Language: C++
Result: Accepted
Time:6872 ms
Memory:56988 kb
****************************************************************/ #include <cstdio>
#include <cmath>
#include <algorithm> using namespace std;
typedef double lf;
typedef long long ll; const int N = 3e5 + ; struct edge {
int next, to;
edge(int _n = , int _t = ) : next(_n), to(_t) {}
} e[N]; struct heap {
heap *ls, *rs;
ll v, tag_t, tag_a;
int dep, st, w; void* operator new(size_t, int x, int y, ll z) {
static heap mempool[N], *c = mempool;
c -> ls = c -> rs = NULL;
c -> dep = , c -> v = z, c -> w = x, c -> st = y;
c -> tag_t = , c -> tag_a = ;
return c++;
} inline void Times(ll x) {
v *= x, tag_t *= x, tag_a *= x;
}
inline void Add(ll x) {
v += x, tag_a += x;
}
inline void push() {
if (ls) ls -> Times(tag_t);
if (rs) rs -> Times(tag_t);
tag_t = ;
if (ls) ls -> Add(tag_a);
if (rs) rs -> Add(tag_a);
tag_a = ;
} #define Dep(p) (p ? p -> dep : 0)
inline void update() {
dep = Dep(rs) + ;
} friend heap* merge(heap *x, heap *y) {
if (!x) return y;
if (!y) return x;
if (x -> v > y -> v) swap(x, y);
x -> push();
x -> rs = merge(x -> rs, y);
if (Dep(x -> rs) > Dep(x -> ls)) swap(x -> ls, x -> rs);
x -> update();
return x;
}
#undef Dep inline heap* pop() {
this -> push();
return merge(ls, rs);
}
} *h[N]; struct tree_node {
int fa, a, dep;
ll h, v;
} tr[N]; inline ll read() {
static ll x, sgn;
static char ch;
x = , sgn = , ch = getchar();
while (ch < '' || '' < ch) {
if (ch == '-') sgn = -;
ch = getchar();
}
while ('' <= ch && ch <= '') {
x = x * + ch - '';
ch = getchar();
}
return sgn * x;
} int n, m;
int first[N], tot;
int ans1[N], ans2[N]; inline void add_edge(int x, int y) {
e[++tot] = edge(first[x], y);
first[x] = tot;
} #define y e[x].to
void dfs(int p) {
int x;
tr[p].dep = tr[tr[p].fa].dep + ;
for (x = first[p]; x; x = e[x].next) {
dfs(y);
h[p] = merge(h[p], h[y]);
}
while (h[p] && h[p] -> v < tr[p].h) {
++ans1[p], ans2[h[p] -> w] = tr[h[p] -> st].dep - tr[p].dep;
h[p] = h[p] -> pop();
}
if (h[p])
if (tr[p].a) h[p] -> Times(tr[p].v);
else h[p] -> Add(tr[p].v);
}
#undef y int main() {
int i, x, c;
ll s;
n = read(), m = read();
for (i = ; i <= n; ++i) tr[i].h = read();
for (i = ; i <= n; ++i) {
x = read(), add_edge(x, i);
tr[i].fa = x , tr[i].a = read(), tr[i].v = read();
}
for (i = ; i <= m; ++i) {
s = read(), c = read();
h[c] = merge(h[c], new(i, c, s)heap);
}
dfs();
while (h[]) {
ans2[h[] -> w] = tr[h[] -> st].dep;
h[] = h[] -> pop();
}
for (i = ; i <= n; ++i) printf("%d\n", ans1[i]);
for (i = ; i <= m; ++i) printf("%d\n", ans2[i]);
return ;
}