BZOJ 2926 Poi1999 空立方体问题

题目大意:给定一个空间上的 n(n5000) 个点,你需要输出一个点 (x,y,z) ,满足:
1. 0x,y,z106
2.不存在一个点 (xi,yi,zi) 满足 0<xi<x,0<yi<y,0<zi<z
3.在此基础上最大化 xyz

考虑二维怎么做
我们将点按横坐标排序,维护一个纵坐标单调递减的序列,那么答案一定是某对相邻点 (p1,p2) 之间的最大矩形 (x2,y1)

现在是三维,我们将点按照第三维从小到大排序并依次加入,那么我们需要动态维护这个单调递减的序列

用set即可

注意由于没有SPJ,有一个 n=1,p1=(1,1,1) 的点需要输出 (1,106,106)

#include <set>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 5050
using namespace std;
struct Point{
    int x,y;
    Point() {}
    Point(int _,int __):
        x(_),y(__) {}
    friend istream& operator >> (istream &_,Point &p)
    {
        return scanf("%d%d",&p.x,&p.y),_;
    }
    bool operator < (const Point &p) const
    {
        if(x!=p.x)
            return x<p.x;
        return y>p.y;
    }
};
int n,ans_x,ans_y,ans_z;
long long ans=-1;
pair<int,Point> points[M];
set<Point> s;
multiset<pair<long long,Point> > _ans;
int main()
{
    int i;
    cin>>n;
    for(i=1;i<=n;i++)
    {
        cin>>points[i].second;
        scanf("%d",&points[i].first);
    }
    points[++n]=make_pair(1000000,Point(0,0));
    sort(points+1,points+n+1);
    s.insert(Point(0,1000000));
    s.insert(Point(1000000,0));
    _ans.insert(make_pair(1000000000000ll,Point(1000000,1000000) ) );
    for(i=1;i<=n;i++)
    {
        multiset<pair<long long,Point> >::iterator it=_ans.end();it--;
        if(points[i].first*it->first>ans)
        {
            ans=points[i].first*it->first;
            ans_x=it->second.x;
            ans_y=it->second.y;
            ans_z=points[i].first;
        }
        if( s.find(points[i].second)!=s.end() )
            continue;
        set<Point>::iterator _it=s.insert(points[i].second).first;
        set<Point>::iterator it_=_it;_it++;it_--;
        if(it_->y<points[i].second.y)
        {
            s.erase(s.find(points[i].second));
            continue;
        }
        _ans.erase(_ans.find(make_pair((long long)_it->x*it_->y,Point(_it->x,it_->y) ) ) );
        while(1)
        {
            set<Point>::iterator temp=_it;temp++;
            if(_it->y<=points[i].second.y) break;
            _ans.erase(_ans.find(make_pair((long long)temp->x*_it->y,Point(temp->x,_it->y) ) ) );
            s.erase(_it);_it=temp;
        }
        _ans.insert(make_pair((long long)points[i].second.x*it_->y,Point(points[i].second.x,it_->y) ) );
        _ans.insert(make_pair((long long)_it->x*points[i].second.y,Point(_it->x,points[i].second.y) ) );
    }
    if(ans_x==1000000&&ans_y==1000000&&ans_z==1)
        swap(ans_x,ans_z);
    cout<<ans_x<<' '<<ans_y<<' '<<ans_z<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值