不得不说出题人的创意特赞!
题面翻译(BZOJ的英文题能不能带翻译QaQ我一开始没看见多组数据):
在一个平面直角坐标系中,有一些关键点,坐标都是整数。现在要求你构造一个点集:
1.包含了所有关键点
2.允许由无数个点叠成一条线段,或是平面
3.任意一条平行于x轴或y轴的直线,与这个点集的公共部分,必须是:空,一个点,或连续的一条线段(也就是中间不能断)
4.满足1,3的条件下,使点集中的平面的面积最小
现在一开始平面上没有关键点,N次操作,每次加入一个关键点,输出N行,每行代表此时的点集的最小面积
题目保证,在任意时刻,整个点集一定是联通的,也就是保证不存在一个不联通的点集满足1和3
设所有x的最小值是lmost,最大值是rmost。根据3性质,对于一条直线X=x0,它与点集的公共部分是线段
以UP[lmost..rmost]为例,因为3性质,不存在一个i使得
当你新加入一个关键点导致UP改变时,有如下两种情况//设原先的y最大值是T
图1是y<=T 图2是Y>T 的情况。
于是我们可以考虑对于所有整数lmost<=X<=rmost,用线段树维护一个UP(DOWN)序列,支持以下操作:
1.区间(单点)变成同一个数
2.询问一个位置X,求X左侧/右侧最近的且>=UP[X]的UP[ANS]
然而怎么得到输出的答案?
先令所有DOWN=0,UP都>0
#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;
}