51nod 1302 矩形面积交 (不要把题目玩工业了。。)

9 篇文章 0 订阅
7 篇文章 0 订阅

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;
}
//楚江微雨里,建业暮钟时。
//漠漠帆来重,冥冥鸟去迟。
//海门深不见,浦树远含滋。
//相送情无限,沾襟比散丝。
//--韦应物《赋得暮雨送李胄》
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值