标签:眼睛 dep lazy || 左偏树 amp namespace lan ini
现在感觉自己的眼睛要瞎了。
我们发现这东西好像挺适合左偏树的啊:骑士在儿子节点死了就不会走到父亲节点,可以直接删去。
考虑到这条性质(而且城池本来就是树),我们在每个城池建一颗关于骑士的树,表示这一坨骑士都可以来到这个城池。
我们把最小值作为骑士的根,那么就可以删根然后统计城池的死亡骑士和骑士到哪座城池。
关于战斗力,我们把骑士树进行一个 lazy 标记就行了,因为我们是从根开始删除的。
注意要考虑挺到最后的骑士。
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const int N = 3e5 + 5;
int n, m, head[N], dot[N << 1], nxt[N << 1], cnt;
ll ans[N], res[N];
void addEdge(const int u, const int v) {
dot[++ cnt] = v; nxt[cnt] = head[u]; head[u] = cnt;
}
ll read() {
ll x = 0, f = 1; char s;
while((s = getchar()) < ‘0‘ || s > ‘9‘) if(s == ‘-‘) f = -1;
while(s >= ‘0‘ && s <= ‘9‘) {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
return x * f;
}
struct LT {
int f[N], son[N][2], dis[N], b[N], dep[N], a[N];
ll val[N], mul[N], add[N], h[N], Val[N];
void sign(const int o, const ll Mul, const ll Add) {
if(! o) return;
val[o] *= Mul; val[o] += Add;
mul[o] *= Mul; add[o] *= Mul; add[o] += Add;
}
void pushDown(const int o) {
sign(son[o][0], mul[o], add[o]);
sign(son[o][1], mul[o], add[o]);
mul[o] = 1, add[o] = 0;
}
int unite(int x, int y) {
if(! x || ! y) return x | y;
pushDown(x), pushDown(y);
if(val[x] > val[y]) swap(x, y);
son[x][1] = unite(son[x][1], y);
if(dis[son[x][0]] < dis[son[x][1]]) swap(son[x][0], son[x][1]);
dis[x] = dis[son[x][1]] + 1;
return x;
}
void init() {
dep[1] = 1;
for(int i = 1; i <= n; ++ i) {
son[i][0] = son[i][1] = dis[i] = 0;
}
int x;
for(int i = 1; i <= n; ++ i) h[i] = read();
for(int i = 2; i <= n; ++ i) {
x = read(), a[i] = read(), Val[i] = read();
addEdge(x, i);
}
for(int i = 1; i <= m; ++ i) {
val[i] = read(), b[i] = read();
mul[i] = 1;
f[b[i]] = unite(f[b[i]], i);
}
}
int del(const int x) {
int l = son[x][0], r = son[x][1];
return unite(l, r);
}
void solve(const int u) {
for(int i = head[u]; i; i = nxt[i]) {
int v = dot[i];
dep[v] = dep[u] + 1; solve(v);
f[u] = unite(f[u], f[v]);
}
while(f[u] && val[f[u]] < h[u]) {
pushDown(f[u]);
++ res[u]; ans[f[u]] = dep[b[f[u]]] - dep[u];
f[u] = del(f[u]);
}
if(a[u]) sign(f[u], Val[u], 0);
else sign(f[u], 1, Val[u]);
}
}T;
int main() {
n = read(), m = read();
T.init(); T.solve(1);
while(T.f[1]) {
T.pushDown(T.f[1]);
ans[T.f[1]] = T.dep[T.b[T.f[1]]];
T.f[1] = T.del(T.f[1]);
}
for(int i = 1; i <= n; ++ i) printf("%lld\n", res[i]);
for(int i = 1; i <= m; ++ i) printf("%lld\n", ans[i]);
return 0;
}
标签:眼睛 dep lazy || 左偏树 amp namespace lan ini
原文地址:https://www.cnblogs.com/AWhiteWall/p/12627103.html