Description
有2N个矩形,这些矩形被标号为0 ~ 2N-1,对于第i个矩形其长宽分别为X[i]与Y[i]。现在要把这2N个矩形分为两组,每组N个,每个矩形恰好分到两组中的一组里。分成两组后,设两组分别为A组、B组,对于每一组矩形,你需要分别完成如下任务:将该组中的N个矩形依次放在一个平面上,可以相互重叠,要求每个矩形的4条边都平行于平面坐标系的X轴或Y轴,矩形在摆放时可以旋转90度后再摆放。N个矩形摆放完后,使这N个矩形共同重叠的面积最大;设A组的最大面积为SA,B组的最大面积为SB。请寻找一种恰当的分组方法,使SA+SB最大,并输出SA+SB的这个极值。
Solution
考虑统一将短边作为x,长边作为y,按x排序后,一定会取第一个矩形的x作为一组矩形的最小x,再枚举另一个矩形的x作为另一组中最小的x然后贪心即可。
考试的时候脑子很不清醒,用了个std::set
,怒刚了两个多小时正解没刚出来(我真是太菜了)。考完后继续改题,改对后发现TLE掉了。。。然后我灵机一动(脑子发抽),咦?区间第k小不就是主席树吗?!于是开始怒刚主席树,刚到晚上一直TLE+WA,后来XIO大佬来帮忙,发现竟是数组开小了(原题中输入n表示有2n个矩形),XIO大佬真是太强啦!!终于A掉了,回顾一下代码,呃?为什么要用主席树??这里不要求可持久化啊,求第k小直接线段树就行了啊。。。
其实题解是优先队列维护。。老K的std写的是splay。。。有人比我更工业?
总结:借用何爷爷暑假集训时的话,数据结构永远只是个工具,不要把题目玩工业了。面对不同的题目,不要生搬硬套,要机智灵活地使用数据结构,才能更节约时间,减少代码量、复杂度。
Code
发一波被玩工业的代码吧。。(其实主席树并不长,,,)
#include<bits/stdc++.h>
using namespace std;
#define For(i , j , k) for (register int i = (j) , i##_end_ = (k) ; i <= i##_end_ ; ++ i)
#define Fordown(i , j , k) for (register int i = (j) , i##_end_ = (k) ; i >= i##_end_ ; -- i)
#define Set(a , b) memset(a , b , sizeof(a))
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) ((int)(a).size())
#define mid ((l + r) >> 1)
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define Mod (1000000007)
typedef long long LL;
template <typename T> inline bool chkmax(T &a , T b) { return a < b ? (a = b , 1) : 0; }
template <typename T> inline bool chkmin(T &a , T b) { return b < a ? (a = b , 1) : 0; }
int _ , __;
char c_;
inline int read()
{
for (_ = 0 , __ = 1 , c_ = getchar() ; !isdigit(c_) ; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; isdigit(c_) ; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
inline void File()
{
#ifdef hany01
freopen("square.in" , "r" , stdin);
freopen("square.out" , "w" , stdout);
#endif
}
const int maxn = 200060;
struct Matrix
{
int x, y;
bool operator < (const Matrix &matrix) const { return x < matrix.x || (x == matrix.x && y < matrix.y); }
}M[maxn << 1];
struct President_Tree
{
int v, lc, rc;
}tr[maxn * 30];
LL Ans;
int n, log2n[maxn << 1], Min[maxn << 1][18], ls[maxn << 1], len, rt[maxn], cnt;
inline void checkmin(int &min1, int &min2, int num) { if (min1 > num) { min2 = min1; min1 = num; } else if (min2 > num) min2 = num; }
int update(int last, int l, int r, int x)
{
int now = ++ cnt;
tr[now] = tr[last];
++ tr[now].v;
if (l < r)
{
if (x <= mid) tr[now].lc = update(tr[last].lc, l, mid, x);
else tr[now].rc = update(tr[last].rc, mid + 1, r, x);
}
return now;
}
inline void Init()
{
n = read();
For(i, 1, (n << 1))
{
M[i].x = read(), M[i].y = read();
if (M[i].x > M[i].y) swap(M[i].x, M[i].y);
ls[i] = M[i].y;
}
sort(M + 1, M + 1 + (n << 1));
sort(ls + 1, ls + 1 + (n << 1));
len = unique(ls + 1, ls + 1 + (n << 1)) - ls - 1;
For(i, 1, n << 1)
rt[i] = update(rt[i - 1], 1, len, lower_bound(ls + 1, ls + 1 + len, M[i].y) - ls);
log2n[1] = 0;
For(i, 2, n << 1) log2n[i] = log2n[i >> 1] + 1;
For(i, 1, n << 1) Min[i][0] = M[i].y;
For(j, 1, log2n[n << 1]) for (int i = 1; i + (1 << j) - 1 <= (n << 1); ++ i) Min[i][j] = min(Min[i][j - 1], Min[i + (1 << (j - 1))][j - 1]);
}
inline int query_st(int l, int r) { return min(Min[l][log2n[r - l + 1]], Min[r - (1 << log2n[r - l + 1]) + 1][log2n[r - l + 1]]); }
inline LL Max(LL a, LL b) { return a > b ? a : b; }
int query(int rt1, int rt2, int l, int r, int k)
{
if (tr[rt2].v - tr[rt1].v < k) return 0;
if (l == r) return l;
int num = tr[tr[rt2].lc].v - tr[tr[rt1].lc].v;
if (num >= k)
return query(tr[rt1].lc, tr[rt2].lc, l, mid, k);
else
return query(tr[rt1].rc, tr[rt2].rc, mid + 1, r, k - num);
}
inline void Solve()
{
ls[0] = INF;
int x1, x2;
LL y1 = INF, y2 = INF;
x1 = 1;
For(i, n + 2, n * 2) chkmin(y2, (LL)M[i].y);
for (x2 = n + 1; x2 >= 2; -- x2)
{
y1 = query_st(x1, x2 - 1);
if (x2 == n + 1)
{
chkmax(Ans, M[x1].x * y1 + M[x2].x * min(y2, (LL)M[x2].y));
chkmin(y2, (LL)M[x2].y);
continue;
}
if (y2 >= y1)
{
chkmax(Ans, M[x1].x * y1 + (LL)M[x2].x * min(ls[query(rt[x2], rt[n << 1], 1, len, n - x2 + 2)], M[x2].y));
}
else
{
chkmax(Ans, M[x1].x * y2 + (LL)M[x2].x * min((LL)ls[query(rt[x2], rt[n << 1], 1, len, n - x2 + 2)], (LL)M[x2].y));
chkmax(Ans, M[x2].x * min((LL)M[x2].y, y2) + M[x1].x * (LL)min(y1, (LL)(ls[query(rt[x2], rt[n << 1], 1, len, n)])));
}
chkmin(y2, (LL)M[x2].y);
}
printf("%lld\n", Ans);
cerr << Ans << endl;
}
int main()
{
File();
Init();
Solve();
return 0;
}
//楚江微雨里,建业暮钟时。
//漠漠帆来重,冥冥鸟去迟。
//海门深不见,浦树远含滋。
//相送情无限,沾襟比散丝。
//--韦应物《赋得暮雨送李胄》