[BZOJ 5059]前鬼后鬼的守护
这不是可并堆裸题吗……我这种傻逼只会用线段树合并做
显然一个集合的中位数可以用平衡树或者权值线段树求出,然后为了方便合并我用了权值线段树。
然后考虑对于一个递减的序列,选择中位数一定更优,一个递增的序列当然xjb选即可。我们可以用一个栈来维护当前的所有答案区间,然后考虑一个新的点加进来。这个点的答案如果比栈首答案小,那么就违反了单调不降的要求,我们需要把两段合并。然后完了……
代码:
/************************************************************** Problem: 5059 User: danihao123 Language: C++ Result: Accepted Time:2348 ms Memory:250520 kb ****************************************************************/ #include <cstdio> #include <cstring> #include <cstdlib> #include <cctype> #include <cassert> #include <algorithm> #include <utility> #include <stack> const int BUFSIZE = 20 * 1024 * 1024; int n; struct Node { Node *lc, *rc; int sumv; }; Node pool[BUFSIZE]; Node *nil, *cur; void init_pool() { cur = nil = pool; nil -> lc = nil -> rc = nil; nil -> sumv = 0; } Node *alloc_node(int v = 0, Node *lc = nil, Node *rc = nil) { cur ++; cur -> lc = lc; cur -> rc = rc; cur -> sumv = v; return cur; } void modify(Node* &o, int L, int R, int p, int v) { if(o == nil) { o = alloc_node(0); } o -> sumv += v; if(L < R) { int M = (L + R) / 2; if(p <= M) { modify(o -> lc, L, M, p, v); } else { modify(o -> rc, M + 1, R, p, v); } } } Node *merge(Node* &tag, Node* &src) { if(src == nil) return tag; if(tag == nil) { return src; } tag -> sumv += src -> sumv; tag -> lc = merge(tag -> lc, src -> lc); tag -> rc = merge(tag -> rc, src -> rc); return tag; } int kth(Node *o, int L, int R, int k) { if(L == R) { return L; } else { int M = (L + R) / 2; if(k <= o -> lc -> sumv) { return kth(o -> lc, L, M, k); } else { return kth(o -> rc, M + 1, R, k - o -> lc -> sumv); } } } void gou_tree(Node *o, int L, int R) { printf("Tree (%d, %d, %d)\n", L, R, o -> sumv); int M = (L + R) / 2; if(L < R) { gou_tree(o -> lc, L, M); gou_tree(o -> rc, M + 1, R); } } int lsiz; const int maxn = 500005; int A[maxn], A2[maxn]; void break_up() { std::sort(A2 + 1, A2 + 1 + n); lsiz = std::unique(A2 + 1, A2 + 1 + n) - A2 - 1; for(int i = 1; i <= n; i ++) { A[i] = std::lower_bound(A2 + 1, A2 + 1 + lsiz, A[i]) - A2; } } struct Interval { Node *rt; int l, r; int siz, ans; Interval() { rt = nil; siz = ans = 0; } Interval(int p) { rt = nil; modify(rt, 1, lsiz, p, 1); siz = 1; ans = p; } }; typedef long long ll; ll solve() { break_up(); init_pool(); std::stack<Interval> S; for(int i = 1; i <= n; i ++) { Interval nv(A[i]); nv.l = nv.r = i; while(!S.empty() && S.top().ans > nv.ans) { Interval g = S.top(); S.pop(); #ifdef LOCAL printf("ans of [%d, %d] : %d\n", g.l, g.r, A2[g.ans]); #endif nv.l = g.l; nv.siz += g.siz; nv.rt = merge(nv.rt, g.rt); #ifdef LOCAL gou_tree(nv.rt, 1, lsiz); #endif nv.ans = kth(nv.rt, 1, lsiz, (nv.siz + 1) / 2); } S.push(nv); } ll ans = 0; while(!S.empty()) { Interval g = S.top(); S.pop(); #ifdef LOCAL printf("ans of [%d, %d] : %d\n", g.l, g.r, A2[g.ans]); #endif for(int i = g.l; i <= g.r; i ++) { ans += abs(A2[A[i]] - A2[g.ans]); } } return ans; } int main() { scanf("%d", &n); for(int i = 1; i <= n; i ++) { scanf("%d", &A[i]); A2[i] = A[i]; } printf("%lld\n", solve()); return 0; }