HDU - 5788 Level Up 主席树 + 树状数组
我们考虑把每个点遍历一遍, 把枚举的当前的这个点改成100000对答案的影响。
如果我们把 u 变成 100000, 受到影响的是 u 以及它的祖先,
我们记midu为子树u的中位数, nexmidu为子树u中位数的下一个数。
只有 a[ u ]的值小于等于祖先的mid, 才会改变祖先的薪水, 变成nexmidu。
所以我们用主席树求出每个子树的mid 和 nexmid。 然后dfs一遍整棵树, 用树状数组去更新答案。
#pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #define fi first #define se second #define mk make_pair #define PLL pair<LL, LL> #define PLI pair<LL, int> #define PII pair<int, int> #define SZ(x) ((int)x.size()) #define ALL(x) (x).begin(), (x).end() #define fio ios::sync_with_stdio(false); cin.tie(0); using namespace std; const int N = 1e5 + 7; const int inf = 0x3f3f3f3f; const LL INF = 0x3f3f3f3f3f3f3f3f; const int mod = 998244353; const double eps = 1e-8; const double PI = acos(-1); template<class T, class S> inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;} template<class T, class S> inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;} template<class T, class S> inline bool chkmax(T& a, S b) {return a < b ? a = b, true : false;} template<class T, class S> inline bool chkmin(T& a, S b) {return a > b ? a = b, true : false;} int n, a[N]; int needVal[N]; int addVal[N]; vector<int> G[N]; int in[N], ot[N], sz[N], idx; LL ans, allVal; struct ChairManTree { int Rt[N], treecnt; void init() { treecnt = 0; } struct Node { int sum, ls, rs; } a[N * 20]; void update(int p, int val, int l, int r, int &x, int y) { x = ++treecnt; a[x] = a[y]; a[x].sum += val; if(l == r) return; int mid = l + r >> 1; if(p <= mid) update(p, val, l, mid, a[x].ls, a[y].ls); else update(p, val, mid + 1, r, a[x].rs, a[y].rs); } int query(int k, int l, int r, int x, int y) { if(l == r) return l; int mid = l + r >> 1; if(a[a[x].ls].sum - a[a[y].ls].sum >= k) return query(k, l, mid, a[x].ls, a[y].ls); else return query(k - a[a[x].ls].sum + a[a[y].ls].sum, mid + 1, r, a[x].rs, a[y].rs); } } C; struct Bit { LL a[N]; void init() { for(int i = 1; i < N; i++) { a[i] = 0; } } inline void update(int x, int v) { for(int i = x; i < N; i += i & -i) { a[i] += v; } } inline LL sum(int x) { LL ans = 0; for(int i = x; i; i -= i & -i) { ans += a[i]; } return ans; } } Tree; int dfs(int u) { in[u] = ++idx; C.update(a[u], 1, 1, 100000, C.Rt[idx], C.Rt[idx - 1]); sz[u] = 1; for(auto &v : G[u]) { dfs(v); sz[u] += sz[v]; } ot[u] = idx; } void solve(int u) { Tree.update(100001 - needVal[u], addVal[u]); chkmax(ans, Tree.sum(100000 - a[u] + 1)); for(auto &v : G[u]) { solve(v); } Tree.update(100001 - needVal[u], -addVal[u]); } void init() { ans = allVal = idx = 0; C.init(); Tree.init(); for(int i = 1; i <= n; i++) { G[i].clear(); } } int main() { while(scanf("%d", &n) != EOF) { init(); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for(int i = 2; i <= n; i++) { int p; scanf("%d", &p); G[p].push_back(i); } dfs(1); for(int i = 1; i <= n; i++) { if(sz[i] == 1) { needVal[i] = a[i]; addVal[i] = 100000 - a[i]; allVal += a[i]; } else { int mid = sz[i] + 1 >> 1; needVal[i] = C.query(mid, 1, 100000, C.Rt[ot[i]], C.Rt[in[i] - 1]); addVal[i] = C.query(mid + 1, 1, 100000, C.Rt[ot[i]], C.Rt[in[i] - 1]) - needVal[i]; allVal += needVal[i]; } } solve(1); printf("%lld\n", ans + allVal); } return 0; } /* */