[BZOJ 5059]前鬼后鬼的守护

danihao123 posted @ 2018年3月04日 18:16 in 题解 with tags BZOJ 权值线段树 线段树合并 , 425 阅读
转载请注明出处:http://danihao123.is-programmer.com/

这不是可并堆裸题吗……我这种傻逼只会用线段树合并做

显然一个集合的中位数可以用平衡树或者权值线段树求出,然后为了方便合并我用了权值线段树。

然后考虑对于一个递减的序列,选择中位数一定更优,一个递增的序列当然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;
}

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter