[BZOJ3845] ZCC loves Minecraft

来源:互联网 发布:淘宝美工一个月多少钱 编辑:程序博客网 时间:2024/04/26 10:32

不得不说出题人的创意特赞
题面翻译(BZOJ的英文题能不能带翻译QaQ我一开始没看见多组数据):
在一个平面直角坐标系中,有一些关键点,坐标都是整数。现在要求你构造一个点集:
1.包含了所有关键点
2.允许由无数个点叠成一条线段,或是平面
3.任意一条平行于x轴或y轴的直线,与这个点集的公共部分,必须是:空,一个点,或连续的一条线段(也就是中间不能断)
4.满足1,3的条件下,使点集中的平面的面积最小

现在一开始平面上没有关键点,N次操作,每次加入一个关键点,输出N行,每行代表此时的点集的最小面积

题目保证,在任意时刻,整个点集一定是联通的,也就是保证不存在一个不联通的点集满足1和3

设所有x的最小值是lmost,最大值是rmost。根据3性质,对于一条直线X=x0,它与点集的公共部分是线段

(x0,DOWNx0)(x0,UPx0)(lmost<=x<=rmost)

以UP[lmost..rmost]为例,因为3性质,不存在一个i使得

UPi1>UPi<UPi+1(lmost<i<rmost)

也就是说,UP一定是一个先不下降,后不上升的序列。同理,DOWN先不上升后不下降

当你新加入一个关键点导致UP改变时,有如下两种情况//设原先的y最大值是T
图1是y<=T 图2是Y>T 的情况。
Fig.1:y不超过原最大值;Fig.2:y超过原最大值
于是我们可以考虑对于所有整数lmost<=X<=rmost,用线段树维护一个UP(DOWN)序列,支持以下操作:
1.区间(单点)变成同一个数
2.询问一个位置X,求X左侧/右侧最近的且>=UP[X]的UP[ANS]

然而怎么得到输出的答案?

先令所有DOWN=0,UP都>0

ANS=i=lmostrmost1min(UP[i],UP[i+1])

上式的正确性是显而易见的,又因为UP是先不降后不升序列,设UP[mid]是最大值,那么:
min(UP[i],UP[i+1])=UP[i](i<mid)

min(UP[i],UP[i+1])=UP[i+1](i>=mid)

结合上式,
ANS=(i=lmostrmostUP[i])maxi=rmosti=lmostUP[i]

那么如果有DOWN存在,结论也是很容易的:
ANS=(i=lmostrmostUP[i])(i=lmostrmostDOWN[i])maxrmosti=lmostUP[i]+minrmosti=lmostDOWN[i]

你可以把DOWN记成相反数,那么只要让你的线段树兹磁区间和询问和区间最大值询问就可以啦!
代码长度不忍直视>_<

#include <cstdio>template <typename Int> inline Int max(Int x, Int y) { return x > y ? x : y; }template <typename Int> inline Int min(Int x, Int y) { return x < y ? x : y; }int I(){    char c = getchar();    int r = 0, f = 0;    while ((c < 48 or c > 57) && c != '-')        c = getchar();    if (c == '-')        f = 1, c = getchar();    while (c > 47 && c < 58)        r = (r << 3) + r + r + c - 48, c = getchar();    return f ? -r : r;}class segmentTree{    public:    void PUT(int x, int y)    {        if (QMax(x, x) < y)        {            if (y <= SegMax[1])            {                int LMt = x > -100000 ? (Ql = -100000, Qr = x - 1, Qw = y, RMostLarger(1, -100000, 100000)) : -1234321237, RMt = x < 100000 ? (Ql = x + 1, Qr = 100000, Qw = y, LMostLarger(1, -100000, 100000)) : 1234321237;                if (LMt != -1234321237)                    Same(LMt + 1, x, y);                else                    Same(x, RMt - 1, y);            }            else            {                int TOPp = MaxPosition(), X = leaf_ref[TOPp], Y = SegMax[TOPp];                if (X < x)                    Same(X, x - 1, Y);                if (X > x)                    Same(x + 1, X, Y);                Set(x, y);            }        }    }    void init() { __init(1, -100000, 100000); }    void Set(int x, int d) { M(x, d); }    void Same(int l, int r, int d) { Ql = l, Qr = r, Qw = d, P(1, -100000, 100000); }    int QMax(int l, int r) { Ql = l, Qr = r; return G(1, -100000, 100000); }    long long QSum(int l, int r) { Ql = l, Qr = r; return S(1, -100000, 100000); }    int MaxPosition()    {        int p = 1;        while (Size[p] > 1)        {            Down(p);            if (SegMax[p] == SegMax[p + p])                p <<= 1;            else                p = p + p + 1;        }        return p;    }    private:    int RMostLarger(int p, int l, int r)    {        if (SegMax[p] < Qw)            return -1234321237;        if (Ql <= l && r <= Qr)        {            int m;            while (Size[p] > 1)            {                m = l + r >> 1;                Down(p);                if (SegMax[p + p + 1] >= Qw)                    l = m + 1, p = p + p + 1;                else                    r = m, p <<= 1;            }            return leaf_ref[p];        }        int __, m = l + r >> 1;        if (Qr > m)            if ((__ = RMostLarger(p + p + 1, m + 1, r)) != -1234321237)                return __;        return Ql <= m ? RMostLarger(p + p, l, m) : -1234321237;    }    int LMostLarger(int p, int l, int r)    {        if (SegMax[p] < Qw)            return 1234321237;        if (Ql <= l && r <= Qr)        {            int m;            while (Size[p] > 1)            {                m = l + r >> 1;                Down(p);                if (SegMax[p + p] >= Qw)                    r = m, p <<= 1;                else                    l = m + 1, p = p + p + 1;            }            return leaf_ref[p];        }        int __, m = l + r >> 1;        if (Ql <= m)            if ((__ = LMostLarger(p + p, l, m)) != 1234321237)                return __;        return Qr > m ? LMostLarger(p + p + 1, m + 1, r) : 1234321237;    }    int Ql, Qr, Qw;    int SegMax[555555], SameTag[555555], Size[555555], leaf_ref[555555];    long long SegSum[555555];    void __init(int p, int l, int r)    {        Size[p] = r - l + 1;        if (l < r)        {            int m = l + r >> 1;            __init(p + p, l, m);            __init(p + p + 1, m + 1, r);        }        else            leaf_ref[p] = l;    }    void Up(int p)    {        SegMax[p] = max(SegMax[p + p], SegMax[p + p + 1]);        SegSum[p] = SegSum[p + p] + SegSum[p + p + 1];    }    void Down(int p)    {        if (SameTag[p])        {            SameTag[p] = 0;            SameTag[p + p] = SameTag[p + p + 1] = 1;            SegMax[p + p] = SegMax[p + p + 1] = SegMax[p];            SegSum[p + p] = (long long)Size[p + p] * SegMax[p];            SegSum[p + p + 1] = (long long)Size[p + p + 1] * SegMax[p];        }    }    int Find(int x)    {        int p = 1, l = -100000, r = 100000, m;        Down(p);        while (l < r)        {            Down(p);            m = l + r >> 1;            if (x <= m)                r = m, p <<= 1;            else                l = m + 1, p = p + p + 1;        }        return p;    }    void P(int p, int l, int r) // makeSame    {        if (Ql <= l && r <= Qr)            SameTag[p] = 1, SegMax[p] = Qw, SegSum[p] = (long long)Size[p] * Qw;        else        {            int m = l + r >> 1;            Down(p);            if (Ql <= m)                P(p + p, l, m);            if (Qr > m)                P(p + p + 1, m + 1, r);            Up(p);        }    }    int G(int p, int l, int r) // get the largest    {        if (Ql <= l && r <= Qr)            return SegMax[p];        Down(p);        int m = l + r >> 1;        int Le = Ql <= m ? G(p + p, l, m) : 0, Ri = Qr > m ? G(p + p + 1, m + 1, r) : 0;        return max(Le, Ri);    }    void M(int x, int d) // a[x] := d    {        int p = Find(x);        SegMax[p] = SegSum[p] = d, SameTag[p] = 0;        while (p > 1)            p >>= 1, Up(p);    }    long long S(int p, int l, int r) // get the sum    {        if (Ql <= l && r <= Qr)            return SegSum[p];        Down(p);        int m = l + r >> 1;        long long Le = Ql <= m ? S(p + p, l, m) : 0, Ri = Qr > m ? S(p + p + 1, m + 1, r) : 0;        return Le + Ri;    }}UP, DOWN;int main(){    UP.init(), DOWN.init();    int Q;    while (scanf("%d", &Q) != EOF)    {        int lmost = 10000000, rmost = -10000000;        UP.Same(-100000, 100000, 0), DOWN.Same(-100000, 100000, 0);        while (Q--)        {            int x = I(), y = I();            UP.PUT(x, 200000 + y), DOWN.PUT(x, 200000 - y);            if (x < lmost)                lmost = x;            if (x > rmost)                rmost = x;            printf("%lld\n", UP.QSum(-100000, 100000) + DOWN.QSum(-100000, 100000) - UP.QMax(-100000, 100000) - DOWN.QMax(-100000, 100000) - 400000ll * (rmost - lmost));        }    }    return 0;}
2 0
原创粉丝点击