这道题算事那个apio里面唯一我能做的题了= =
链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2809
题目一看完很容易想到一个贪心,然后我们需要维护以某一个节点为根的权值大小关系,如果知道一个子树的大小关系那么子树的根作为管理员的答案就可以求了。然后子树合并= =splay 可搞,大多数说的左偏树(某种堆)也可以,还有很多= =搞搞就好= =我总结一下左偏树:
1.merge 和smt 一样
2.维护val 和dis, 保证lson的dis > rson 的dis
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long qword; const qword maxn = 100100; qword n, S, v[maxn], c[maxn]; struct node { qword val, dis, size, sum; node *l, *r; }e[maxn], *rt[maxn]; qword ne = 0; void swap(node* &a, node* &b) { node* x = a; a = b; b = x; } void update(node* now) { now-> size = 1, now-> sum = now-> val; if(now-> l) now-> size += now-> l-> size, now-> sum += now-> l-> sum; if(now-> r) now-> size += now-> r-> size, now-> sum += now-> r-> sum; } node* merge(node* a, node* b) { if(!a) return b; if(!b) return a; if(a-> val < b-> val) swap(a, b); a-> r = merge(a-> r, b); qword dl = a-> l ? a-> l-> dis : -1; qword dr = a-> r ? a-> r-> dis : -1; if(dl < dr) swap(a-> l, a-> r); a-> dis = a-> r ? a-> r-> dis + 1 : 0; update(a); return a; } void pop(node* &a) { a = merge(a-> l, a-> r); } qword top(node* a) { return a ? a-> val : -1; } struct edge { qword t; edge* next; }se[maxn * 2], *head[maxn]; qword oe = 0; void addedge(qword f, qword t) { se[oe].t = t, se[oe].next = head[f], head[f] = se + oe ++; } void read() { scanf("%lld%lld", &n, &S); for(qword i = 1; i <= n; ++ i) { qword u; scanf("%lld%lld%lld", &u, &v[i], &c[i]); if(u) addedge(u, i), addedge(i, u); } } qword ans = 0; void sov() { for(qword i = n; i >= 1; -- i) { rt[i] = e + ne ++; rt[i]-> val = v[i], rt[i]-> size = 1, rt[i]-> sum = rt[i]-> val; rt[i]-> l = rt[i]-> r = NULL; for(edge* p = head[i]; p; p = p-> next) { if(p-> t > i) { rt[i] = merge(rt[i], rt[p-> t]); } } while(rt[i] && rt[i]-> sum > S) pop(rt[i]); if(rt[i]) ans = max(ans, rt[i]-> size * c[i]); } printf("%lld\n", ans); } int main() { //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); read(), sov(); return 0; }