bzoj1367: [Baltic2004]sequence

题解

首先我们看,对于一段区间[l,r],他们如果是递增的,那么最优解就是对于z[i]=t[i],i[l,r],如果是递减的话那么最优解就是中位数了,即z[i]=t[(l+r)/2],i[l,r]如果我们把递增的区间拆成一个点一个点的,现在的序列就相当于有很多段递减的区间构成辣,那么现在的问题就是有很多段连续的区间,然后每段的答案都为一个值。我们考虑如何合并两段区间的答案.
假设我们要合并区间[l,n],[n+1,r]这两段区间,他们的最优解分别是{u,u,u,u},{u,u,u,u}
假设合并后答案为

{b[l],b[l+1],b[l+2],b[n],b[n+1],b[n+2],b[n+3],b[r]}
那么明显的,b[n]<=u,b[n+1]>=u假如b[n]>u,那么我们可以将{b[l],b[l+1],b[l+2],b[n]}变为{u,u,u,u},显然更优,对于b[n+1]>=u同理.
然后结合绝对值的几何意义,我们可以解改为
{b[n],b[n],b[n],b[n],b[n+1],b[n+1],b[n+1],b[n+1]}
当b[n+1]>u时,b[n]显然应该=u,而当b[n]=u时,显然b[n+1]=u时原式最小。当u’<=b[n+1]<=u时,显然b[n]等于b[n+1]时原式最小,综上所述原式最小时b[n]一定等于b[n+1],当b[n]=b[n+1]=w时,原式最小(w为两段序列的中位数)。那么合并后的两段区间的解变为
{w,w,w,w,w,w,w,w}

然后现在一个很容易想到的做法是用平衡树来维护中位数,复杂度两个log.
然后我们发现,按照上面的合并方式的话,我们也可以把递减的序列拆成一个一个的,我们可以把问题转化成一个元素一个元素的加入,维护单调的一个当前的解集。然后我们看加入一个元素后两段区间A,B被合并的情况,很显然当加入这个元素前,AmidA<BmidB然后加入后AmidA>BmidB(这样他们才有可能被合并),这就说明BmidA一定大于max{x,BmidB1}BmidA一定是两段序列中的第midA+midB大的数,那么midA,midB的奇偶进行简单的讨论一下后,会发现如果我们直接维护的A序列前midA个数和B序列前midB个数的话,然后将这些数合并的话,新序列C的前midC 个数一定出现且仅出现在这里面。所以我们可以对每一个序列维护前mid个数就ok了

#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;
}
posted @ 2017-01-03 08:42  DraZxlnDdt  阅读(180)  评论(0编辑  收藏  举报