bzoj1367: [Baltic2004]sequence
题解
首先我们看,对于一段区间[l,r],他们如果是递增的,那么最优解就是对于
假设我们要合并区间[l,n],[n+1,r]这两段区间,他们的最优解分别是{
假设合并后答案为
然后结合绝对值的几何意义,我们可以解改为
然后现在一个很容易想到的做法是用平衡树来维护中位数,复杂度两个log.
然后我们发现,按照上面的合并方式的话,我们也可以把递减的序列拆成一个一个的,我们可以把问题转化成一个元素一个元素的加入,维护单调的一个当前的解集。然后我们看加入一个元素后两段区间A,B被合并的情况,很显然当加入这个元素前,
#include<cstdio>
#include<cstring>
#include<algorithm>
const int N = 1e6 + 9;
int n;
void G (int &num) {
static char a; static bool fl;
for (a = getchar (), fl = false; a > '9' || a < '0'; a = getchar ()) if (a == '-') fl = true;
for (num = 0; a >= '0' && a <= '9'; a = getchar ()) num = (num << 3) + (num << 1) + a - '0';
if (fl) num = -num;
}
void IO () {
freopen ("1367.in", "r", stdin);
freopen ("1367.out", "w", stdout);
}
struct LT {
int data, dist, size;
LT *l, *r;
void set () { data = dist = size = 0; l = r = this; }
void update () { dist = r -> dist + 1; size = l -> size + r -> size + 1; }
LT () {}
LT (int x, LT *fl) : data (x), dist (1), size (1), l (fl), r (fl) {}
}*Null, *root[N], pool[N], *pis = pool;
LT* Merge (LT *A, LT *B) {
if (A == Null) return B;
if (B == Null) return A;
if (A -> data < B -> data) std :: swap (A, B);
A -> r = Merge (A -> r, B);
if (A -> l -> dist < A -> r -> dist) std :: swap (A -> l, A -> r);
A -> update ();
return A;
}
LT* newnode (int xxx) {
return new (pis++) LT (xxx, Null);
}
void Pop (LT *&x) {
x = Merge (x -> l, x -> r);
}
int t[N], x, top, c[N], w[N], l[N], r[N];
void Solve () {
Null = new (pis++) LT ();
Null -> set ();
G (n);
for (int i = 1; i <= n; ++i) {
scanf ("%d", &x); x -= i; w[i] = x;
root[++top] = newnode (x);
l[top] = r[top] = i;
c[top] = 1;
while (top > 1 && root[top] -> data < root[top - 1] -> data) {
--top;
root[top] = Merge (root[top], root[top + 1]);
if ((c[top] & 1) && (c[top + 1] & 1)) Pop (root[top]);
r[top] = r[top + 1];
c[top] += c[top + 1];
}
}
long long ret = 0;
for (int i = 1; i <= top; ++i) {
for (int j = l[i]; j <= r[i]; ++j) {
ret += abs (w[j] - root[i] -> data);
}
}
printf ("%lld\n", ret);
}
int main () {
// IO ();
Solve ();
return 0;
}