[洛谷P3261][JLOI2015]城池攻佔
阿新 • • 發佈:2018-12-05
題目大意:有$n$個點的樹,第$i$個節點有一個權值$h_i$,$m$個騎士,第$i$個騎士攻擊力為$v_i$,一個騎士可以把從它開始的連續的父親中比它小的節點攻破,攻破一個節點可以把攻擊力加或乘一個數(乘的數大於$0$)(每個騎士獨立),問每個騎士可以攻破多少個點,每個點會阻擋住多少個騎士。
題解:可以把所有騎士一起考慮,建一個小根堆,存可以攻打到這個點的騎士,每個若堆頂小於該點,就彈出,寫一個打標記的可並堆就行了。
卡點:快讀中讀入$long\;long$的部分返回值變成$int$
C++ Code:
#include <algorithm> #include <cstdio> #include <cctype> namespace __IO { namespace R { int x, ch, f; inline int read() { ch = getchar(); f = 1; while (isspace(ch)) ch = getchar(); if (ch == '-') f = -1, ch = getchar(); for (x = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) x = x * 10 + (ch & 15); return x * f; } long long X; inline long long readll() { ch = getchar(); f = 1; while (isspace(ch)) ch = getchar(); if (ch == '-') f = -1, ch = getchar(); for (X = ch & 15, ch = getchar(); isdigit(ch); ch = getchar()) X = X * 10 + (ch & 15); return X * f; } } } using __IO::R::read; using __IO::R::readll; #define maxn 300010 int head[maxn], cnt; struct Edge { int to, nxt; } e[maxn << 1]; inline void addedge(int a, int b) { e[++cnt] = (Edge) {b, head[a]}; head[a] = cnt; } namespace Heap { int fa[maxn], lc[maxn], rc[maxn], dis[maxn]; long long M[maxn], A[maxn], V[maxn]; inline void Mul(int rt, long long num) { if (rt) M[rt] *= num, A[rt] *= num, V[rt] *= num; } inline void Add(int rt, long long num) { if (rt) A[rt] += num, V[rt] += num; } inline void pushdown(int rt) { long long &__M = M[rt], &__A = A[rt]; if (__M != 1) { Mul(lc[rt], __M); Mul(rc[rt], __M); __M = 1; } if (__A) { Add(lc[rt], __A); Add(rc[rt], __A); __A = 0; } } int __merge(int x, int y) { if (!x || !y) return x | y; pushdown(x), pushdown(y); if (V[x] > V[y]) std::swap(x, y); rc[x] = __merge(rc[x], y), fa[rc[x]] = x; if (dis[lc[x]] < dis[rc[x]]) std::swap(lc[x], rc[x]); dis[x] = dis[rc[x]] + 1; return x; } int merge(int x, int y) { fa[x] = fa[y] = 0; return __merge(x, y); } int insert(int rt, long long val, int pos) { V[pos] = val, M[pos] = 1, A[pos] = 0; return merge(rt, pos); } int pop(int rt) { pushdown(rt); return merge(lc[rt], rc[rt]); } } int n, m; int a[maxn], c[maxn], dead[maxn], num[maxn]; int rt[maxn], dep[maxn]; long long w[maxn], v[maxn]; void dfs(int u) { for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; dep[v] = dep[u] + 1; dfs(v); rt[u] = Heap::merge(rt[u], rt[v]); } while (rt[u] && Heap::V[rt[u]] < w[u]) { num[u]++, dead[rt[u]] = u; rt[u] = Heap::pop(rt[u]); } if (rt[u]) { if (a[u]) Heap::Mul(rt[u], v[u]); else Heap::Add(rt[u], v[u]); } } int main() { n = read(), m = read(); for (int i = 1; i <= n; i++) w[i] = readll(); for (int i = 2, fa; i <= n; i++) { fa = read(), a[i] = read(), v[i] = readll(); addedge(fa, i); } for (int i = 1; i <= m; i++) { long long V = readll(); c[i] = read(); rt[c[i]] = Heap::insert(rt[c[i]], V, i); } dfs(dep[1] = 1); for (int i = 1; i <= n; i++) printf("%d\n", num[i]); for (int i = 1; i <= m; i++) printf("%d\n", dep[c[i]] - dep[dead[i]]); return 0; }