P3261 [JLOI2015] 城池攻占
题面太长就不复述了,这是一道左偏树的题目,经过简要分析,我们得知对于一个骑士来说,他所走的路径是唯一且单调的,因此我们可以考虑通过拓扑序来遍历。
对于每个点维护一个左偏树,存储当前节点的骑士的参数,那么一个节点的骑士可以由若干子节点的左偏树合并而来。
由于 \(a\) 和 \(v\) 的存在会使得我们骑士参数改变,但我们不可能遍历每一个骑士修改它的参数,我们此时可以采用懒标记保存信息。
每个城市骑士战死的个数可以通过弹出堆顶来得出,由于骑士在树上始终向根节点攻城,所以处理出每个骑士的初始点和终止点求深度差即可。
利用左偏树,可以做到时间复杂度 \(O(n \log n)\)。
参考代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 10;
int n, m, f[N], c[N], dep[N], death[N];
int root[N];
ll h[N], a[N], v[N];
struct Node {
ll v, add, mul;
int l, r, dist, city;
}tr[N];
bool cmp(int x, int y) {
if (tr[x].v != tr[y].v) return tr[x].v > tr[y].v;
return x > y;
}
void pushdown(int u) {
if (tr[u].l) {
tr[tr[u].l].mul *= tr[u].mul;
tr[tr[u].l].add *= tr[u].mul;
tr[tr[u].l].add += tr[u].add;
tr[tr[u].l].v *= tr[u].mul;
tr[tr[u].l].v += tr[u].add;
}
if (tr[u].r) {
tr[tr[u].r].mul *= tr[u].mul;
tr[tr[u].r].add *= tr[u].mul;
tr[tr[u].r].add += tr[u].add;
tr[tr[u].r].v *= tr[u].mul;
tr[tr[u].r].v += tr[u].add;
}
tr[u].mul = 1;
tr[u].add = 0;
}
int merge(int x, int y) {
if (!x || !y) return x | y;
if (cmp(x, y)) swap(x, y);
pushdown(x), pushdown(y);
tr[x].r = merge(tr[x].r, y);
if (tr[tr[x].l].dist < tr[tr[x].r].dist) swap(tr[x].l, tr[x].r);
tr[x].dist = tr[tr[x].r].dist + 1;
return x;
}
void pop(int &x) {
pushdown(x);
x = merge(tr[x].l, tr[x].r);
}
void modify(int u, int x) {
if (!a[x]) {
tr[u].v += v[x];
tr[u].add += v[x];
}
else {
tr[u].v *= v[x];
tr[u].mul *= v[x];
tr[u].add *= v[x];
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> m;
dep[0] = -1;
for (int i = 1; i <= n; i ++ ) cin >> h[i];
for (int i = 2; i <= n; i ++ ) cin >> f[i] >> a[i] >> v[i], dep[i] = dep[f[i]] + 1;
for (int i = 1; i <= m; i ++ ) {
cin >> tr[i].v >> c[i], tr[i].mul = 1;
root[c[i]] = merge(root[c[i]], i);
}
for (int i = n; i; i -- ) {
while (root[i] && h[i] > tr[root[i]].v) {
death[i] ++ ;
tr[root[i]].city = i;
pop(root[i]);
}
if (i == 1) break;
modify(root[i], i);
root[f[i]] = merge(root[f[i]], root[i]);
}
for (int i = 1; i <= n; i ++ ) cout << death[i] << "\n";
for (int i = 1; i <= m; i ++ ) cout << dep[c[i]] - dep[tr[i].city] << "\n";
return 0;
}

浙公网安备 33010602011771号