Luogu 3261 [JLOI2015]城池攻占
BZOJ 4003
需要实现一个可并堆。
每个点维护一个小根堆,然后一开始把所有骑士加入到它所在的点的小根堆当中,实际上空间是$O(m)$的,然后我们从上到下不断合并这个小根堆,合并完之后如果遇到堆顶小于当前城市的防御值就弹掉堆顶顺便记录答案。
对于那些攻占掉城池对骑士的贡献的处理,可以采用打标记的方式实现,在合并的时候$down$一下就好了。注意$down$要写在$merge$函数的最上面,因为有一些点还没有下传标记就被$merge$掉了。
要注意弹出堆顶元素之前要先$down$一下 。
最后在清空一下第一个堆中的元素就好了。
不会算时间复杂度$QωQ$。
Code:
// luogu-judger-enable-o2 #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int N = 3e5 + 5; int n, m, tot = 0, head[N], type[N], dep[N], ans[N]; ll def[N], rat[N]; struct Knight { int pos, ed; ll atk; } a[N]; struct Edge { int to, nxt; } e[N << 1]; inline void add(int from, int to) { e[++tot].to = to; e[tot].nxt = head[from]; head[from] = tot; } template <typename T> inline void read(T &X) { X = 0; char ch = 0; T op = 1; for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') op = -1; for(; ch >= '0' && ch <= '9'; ch = getchar()) X = (X << 3) + (X << 1) + ch - 48; X *= op; } template <typename T> inline void swap(T &x, T &y) { T t = x; x = y; y = t; } namespace LeftlistTree { struct Node { int lc, rc, dis, id; ll key, mulTag, addTag; } s[N]; #define lc(p) s[p].lc #define rc(p) s[p].rc #define key(p) s[p].key #define mulTag(p) s[p].mulTag #define addTag(p) s[p].addTag #define dis(p) s[p].dis #define id(p) s[p].id int root[N], nodeCnt = 0; inline int newNode(int p) { ++nodeCnt; lc(nodeCnt) = rc(nodeCnt) = 0; dis(nodeCnt) = 0; id(nodeCnt) = p; key(nodeCnt) = a[p].atk; addTag(nodeCnt) = 0LL, mulTag(nodeCnt) = 1LL; return nodeCnt; } inline void down(int p) { if(!p) return; if(mulTag(p) != 1) { if(lc(p)) { key(lc(p)) *= mulTag(p); addTag(lc(p)) *= mulTag(p); mulTag(lc(p)) *= mulTag(p); } if(rc(p)) { key(rc(p)) *= mulTag(p); addTag(rc(p)) *= mulTag(p); mulTag(rc(p)) *= mulTag(p); } mulTag(p) = 1; } if(addTag(p) != 0) { if(lc(p)) { key(lc(p)) += addTag(p); addTag(lc(p)) += addTag(p); } if(rc(p)) { key(rc(p)) += addTag(p); addTag(rc(p)) += addTag(p); } addTag(p) = 0; } } int merge(int x, int y) { down(x), down(y); if(!x || !y) return x + y; if(key(x) > key(y)) swap(x, y); rc(x) = merge(rc(x), y); if(dis(lc(x)) < dis(rc(x))) swap(lc(x), rc(x)); dis(x) = dis(rc(x)) + 1; return x; } } using namespace LeftlistTree; void solve(int x, int fat, int depth) { dep[x] = depth; for(int i = head[x]; i; i = e[i].nxt) { int y = e[i].to; if(y == fat) continue; solve(y, x, depth + 1); root[x] = merge(root[x], root[y]); } for(; root[x] && key(root[x]) < def[x]; ) { ++ans[x]; a[id(root[x])].ed = x; down(root[x]); root[x] = merge(lc(root[x]), rc(root[x])); } if(root[x]) { if(!type[x]) { key(root[x]) += rat[x]; addTag(root[x]) += rat[x]; } else { key(root[x]) *= rat[x]; mulTag(root[x]) *= rat[x]; addTag(root[x]) *= rat[x]; } } } int main() { // freopen("3.in", "r", stdin); // freopen("my.out", "w", stdout); read(n), read(m); for(int i = 1; i <= n; i++) read(def[i]); for(int fat, i = 2; i <= n; i++) { read(fat); add(fat, i), add(i, fat); read(type[i]), read(rat[i]); } for(int i = 1; i <= m; i++) { read(a[i].atk), read(a[i].pos); root[a[i].pos] = merge(root[a[i].pos], newNode(i)); } solve(1, 0, 1); for(int i = 1; i <= n; i++) printf("%d\n", ans[i]); for(; root[1]; ) { a[id(root[1])].ed = 0; down(root[1]); root[1] = merge(lc(root[1]), rc(root[1])); } for(int i = 1; i <= m; i++) printf("%d\n", dep[a[i].pos] - dep[a[i].ed]); return 0; }