[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,它与点集的公共部分是线段
以UP[lmost..rmost]为例,因为3性质,不存在一个i使得
也就是说,UP一定是一个先不下降,后不上升的序列。同理,DOWN先不上升后不下降
当你新加入一个关键点导致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
上式的正确性是显而易见的,又因为UP是先不降后不升序列,设UP[mid]是最大值,那么:
结合上式,
那么如果有DOWN存在,结论也是很容易的:
你可以把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
- [BZOJ3845] ZCC loves Minecraft
- HDU4882-ZCC Loves Codefires
- HDU4876 ZCC loves cards
- HDU4876:ZCC loves cards
- hdu5230 ZCC loves hacking
- HDU5229 ZCC loves strings
- ZCC loves straight flush
- HDU5229-ZCC loves strings
- BZOJ3850 ZCC Loves Codefires
- bzoj3850: ZCC Loves Codefires
- BZOJ3840: ZCC Loves COT
- BZOJ3841: ZCC Loves Intersection
- BZOJ3843: ZCC loves Army
- BZOJ3844: ZCC loves cards
- hdu 4882 ZCC Loves Codefires
- HDOJ 4882 ZCC Loves Codefires
- hdu 4882ZCC Loves Codefires
- HDU 4876 ZCC loves cards
- 51nod(1183)——dp
- iOS 开发 -- Swift (十二) 懒加载
- iOS-OC-基本控件之UIPageControl
- OpenGL入门学习(十三)
- iOS文件解析之XML解析
- [BZOJ3845] ZCC loves Minecraft
- android开发练习三-Retrofit
- Android蓝牙连接,传输数据
- C#Winform中DataGridView控件下的右键菜单事件获取行值方法
- K均值
- 我认识的回调函数
- ORACLE中SID和SERVICE_NAME的区别
- 结构体大小计算之位域字段
- 二分静态查找