1 条题解
-
0
思路:
简单题,考虑势能,由于技能值只增不减,所以若现在能在这个地方卖出糖果,则以后肯定也可以。
故问题相当于:
-
每个点初始权值为 。
-
子树权值加。
-
显然一个点能卖出糖果当且仅当 ;询问一条从根出发的路径中能卖出糖果的点的数量的最大值。
考虑线段树快速找到最新 的点,即初始权值为 ,维护区间最大值,支持区间加,若 了则往下找;找到后赋值为 。
考虑若一个点 能卖出糖果对答案的贡献,显然到 子树内的点的答案都会增加一。
故维护两个线段树,一个维护势能找最新可以卖糖果的点,一个用来维护答案。
时间复杂度为 。
完整代码:
#include<bits/stdc++.h> #define lowbit(x) x & (-x) #define ls(k) k << 1 #define rs(k) k << 1 | 1 #define fi first #define se second #define ctz(x) __builtin_ctz(x) #define popcnt(x) __builtin_popcount(x) #define open(s1, s2) freopen(s1, "r", stdin), freopen(s2, "w", stdout); using namespace std; typedef __int128 __; typedef long double lb; typedef double db; typedef unsigned long long ull; typedef long long ll; bool Begin; const int N = 5e5 + 10; inline ll read(){ ll x = 0, f = 1; char c = getchar(); while(c < '0' || c > '9'){ if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9'){ x = (x << 1) + (x << 3) + (c ^ 48); c = getchar(); } return x * f; } inline void write(ll x){ if(x < 0){ putchar('-'); x = -x; } if(x > 9) write(x / 10); putchar(x % 10 + '0'); } int n, q, u, x, cnt; int fa[N], id[N], siz[N], dfn[N]; ll lim[N]; vector<int> E[N]; inline void dfs(int u){ siz[u] = 1; dfn[u] = ++cnt; id[cnt] = u; for(auto v : E[u]){ dfs(v); siz[u] += siz[v]; } } namespace Seg{ struct Node{ int l, r; int Max, tag; }X[N << 2]; inline void pushup(int k){ X[k].Max = max(X[k << 1].Max, X[k << 1 | 1].Max); } inline void add(int k, int v){ X[k].Max += v; X[k].tag += v; } inline void push_down(int k){ if(X[k].tag){ add(k << 1, X[k].tag); add(k << 1 | 1, X[k].tag); X[k].tag = 0; } } inline void build(int k, int l, int r){ X[k].l = l, X[k].r = r; if(l == r) return ; int mid = (l + r) >> 1; build(k << 1, l, mid); build(k << 1 | 1, mid + 1, r); } inline void update(int k, int l, int r, int v){ if(X[k].l == l && r == X[k].r){ add(k, v); return ; } push_down(k); int mid = (X[k].l + X[k].r) >> 1; if(r <= mid) update(k << 1, l, r, v); else if(l > mid) update(k << 1 | 1, l, r, v); else{ update(k << 1, l, mid, v); update(k << 1 | 1, mid + 1, r, v); } pushup(k); } inline int getmax(){ return X[1].Max; } } inline void Add(int u, int v){ Seg::update(1, dfn[u], dfn[u] + siz[u] - 1, v); } namespace Tree{ struct Node{ int l, r; ll Max, tag; }X[N << 2]; inline void pushup(int k){ X[k].Max = max(X[k << 1].Max, X[k << 1 | 1].Max); } inline void add(int k, int v){ X[k].Max += v; X[k].tag += v; } inline void push_down(int k){ if(X[k].tag){ add(k << 1, X[k].tag); add(k << 1 | 1, X[k].tag); X[k].tag = 0; } } inline void build(int k, int l, int r){ X[k].l = l, X[k].r = r; if(l == r){ X[k].Max = -lim[id[l]]; return ; } int mid = (l + r) >> 1; build(k << 1, l, mid); build(k << 1 | 1, mid + 1, r); pushup(k); } inline void update(int k, int l, int r, int v){ if(l > r) return ; if(X[k].l == l && r == X[k].r){ add(k, v); return ; } push_down(k); int mid = (X[k].l + X[k].r) >> 1; if(r <= mid) update(k << 1, l, r, v); else if(l > mid) update(k << 1 | 1, l, r, v); else{ update(k << 1, l, mid, v); update(k << 1 | 1, mid + 1, r, v); } pushup(k); } inline void find(int k){ if(X[k].Max < 0) return ; if(X[k].l == X[k].r){ Add(id[X[k].l], 1); X[k].Max = LONG_LONG_MIN; return ; } push_down(k); find(k << 1), find(k << 1 | 1); pushup(k); } }; bool End; int main(){ n = read(), q = read(); for(int i = 2; i <= n; ++i){ fa[i] = read(); E[fa[i]].push_back(i); } for(int i = 1; i <= n; ++i) lim[i] = read(); dfs(1); Seg::build(1, 1, n), Tree::build(1, 1, n); while(q--){ u = read(), x = read(); Tree::update(1, dfn[u], dfn[u] + siz[u] - 1, x); Tree::find(1); write(Seg::getmax()); putchar('\n'); } cerr << '\n' << abs(&Begin - &End) / 1048576 << "MB"; return 0; } -
- 1
信息
- ID
- 10932
- 时间
- 3000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者