Pre
这道题难度不是很大,也不重要,大佬请不要浪费时间。
Solution
对于每一个节点深搜,合并每个节点上面没死掉的士兵,当然包括这个节点自己上面的,然后取这当中(val)小的,如果小于这个节点的要求,就死掉。
至于懒标记的使用,和洛谷的线段树2模板一样。
Code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 300000 + 5;
struct Graph {
int fr[N], to[N], h[N], tot;
inline void add (int u, int v) {
tot++;
fr[tot] = h[u];
to[tot] = v;
h[u] = tot;
}
}gg;
struct Heap {
int fa[N], ch[N][2], dis[N];
ll tags[N], tagm[N], val[N];
inline int Find (int u) {return fa[u] == u ? u : fa[u] = Find (fa[u]);}
inline void push_down (int p) {
if (tagm[p] != 1) {
val[p] *= tagm[p];
tags[ch[p][0]] *= tagm[p];
tagm[ch[p][0]] *= tagm[p];
tags[ch[p][1]] *= tagm[p];
tagm[ch[p][1]] *= tagm[p];
tagm[p] = 1;
}
if (tags[p]) {
val[p] += tags[p];
tags[ch[p][0]] += tags[p];
tags[ch[p][1]] += tags[p];
tags[p] = 0;
}
}
inline int merge (int u, int v) {
if (u == v) {return u;}
if (!u || !v) {return u + v;}
push_down (u), push_down (v);
if (val[u] > val[v]) {swap (u, v);}
ch[u][1] = merge (ch[u][1], v);
fa[ch[u][1]] = u;
if (dis[ch[u][1]] > dis[ch[u][0]]) {swap (ch[u][0], ch[u][1]);}
dis[u] = dis[ch[u][1]] + 1;
return u;
}
inline void del (int p) {
p = Find (p);
push_down (p);
ch[p][0] = merge (ch[p][0], ch[p][1]);
fa[ch[p][0]] = ch[p][0];
fa[p] = ch[p][0];
ch[p][0] = ch[p][1] = 0;
}
}uu;
struct Tmp {
int p, des;
Tmp (int x = 0, int y = 0) {
p = x, des = y;
}
}info[N];
int n, m, a[N], cnt[N], ans[N], dep[N], id[N], suf[N];
ll h[N], v[N];
inline void dfs (int u, int f) {
dep[u] = dep[f] + 1;
for (int i = gg.h[u]; i; i = gg.fr[i]) {
dfs (gg.to[i], u);
if (id[u]) {
int x = uu.Find(id[u]), y = uu.Find(id[gg.to[i]]);
id[u] = uu.merge(x, y);
}
else {
id[u] = id[gg.to[i]];
}
}
if (id[u]) {
int now = uu.Find (id[u]);
uu.push_down(now);
while (uu.val[now] < h[u]) {
cnt[u]++;
ans[now] = u;
int tmp = uu.ch[now][0] ? uu.ch[now][0] : uu.ch[now][1];
uu.del (now);
now = uu.Find (tmp);
if (!now) {break;}
uu.push_down(now);
}
id[u] = now = uu.Find (now);
if (u == 1) {
return ;
}
if (a[u]) {
uu.tagm[now] *= v[u];
uu.tags[now] *= v[u];
}
else {
uu.tags[now] += v[u];
}
}
}
inline void init () {
for (int i = 1; i <= m; ++i) {
if (i != 1 && info[i].des == info[i - 1].des) {
int u = uu.Find(info[i].p) , v = uu.Find(info[i - 1].p);
uu.merge (u, v);
}
else {
id[info[i].des] = info[i].p;
}
}
}
int main () {
memset (ans, -1, sizeof (ans));
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {scanf ("%lld", &h[i]);}
for (int i = 2; i <= n; ++i) {
int f;
scanf ("%d%d%lld", &f, &a[i], &v[i]);
gg.add(f, i);
}
for (int i = 1; i <= m; ++i) {
uu.fa[i] = i;
uu.tagm[i] = 1;
int c;
scanf ("%lld%d", &uu.val[i], &c);
suf[i] = c;
info[i] = Tmp (i, c);
}
sort (info + 1, info + m + 1, [](Tmp m, Tmp n) {return m.des < n.des;});
init ();
dfs (1, 0);
for (int i = 1; i <= n; ++i) {printf ("%d
", cnt[i]);}
for (int i = 1; i <= m; ++i) {
printf ("%d
", dep[suf[i]] - dep[ans[i]]);
}
return 0;
}
Conclusion
猛然发现结构体还是很好用的。
其次是维护乘(&)加的标记的操作有必要熟悉一下,还有之前的一些常用的技巧。