SPOJ Ada and Field (set,multiset)

题意:给你T个例子,然后给出N,M,Q(2e9,2e9,1e5),即给出了一个(0,0)到(N,M)的矩形
现在有Q次询问,0 a 表示在x轴的a处画一条平行于y轴的分割线。1 a 表示在y轴的a处画一条平行于x轴的平行线
问每一次分割后最大的矩形面积为多少。
思路:一开始拿到这道题我想到了线段树,然而...怎么更新边长(单点更新割点然后来维护区间最长段?)(当然用线段树是肯定能做的)
看了网上题解之后 基本上都是使用的set 以及 multiset来做(因为2s多)。这里就当熟悉set的操作换一种来做吧。
multiset可以保留多个重复的边,同时还自带二分排序。 multiset.erase(multiset.find(a)); 可以只消除集合中一个a,multiset.erase(a);则会删除集合中所有a.

code:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn = 20000 + 10;
set<ll> x, y;//分割点用set存储
multiset<ll> lenx, leny;//边长用mulity来存储
int main(){
    int T;
    ll n, m, q;
    scanf("%d", &T);
    while(T--){
        scanf("%lld%lld%lld", &n, &m, &q);
        x.clear(),y.clear();
        lenx.clear(),leny.clear();
        x.insert(0),x.insert(n),lenx.insert(n);
        y.insert(0),y.insert(m),leny.insert(m);
        set<ll>::iterator it;
        while(q--){
            ll  p;
            int op;
            scanf("%d%lld", &op, &p);
            if(op == 0 && x.count(p) == 0){
                //如果切线p不存在,找到比p大的第一个位置,插入这个位置的左边
                it = x.lower_bound(p);
                //加入新分割出的右边的边
                lenx.insert(*it - p);
                //将长为len的消掉(对应的边)
                int len = *it - *(--it);
                lenx.erase(lenx.find(len));
                //插入左边的边
                lenx.insert(p - *it);
                x.insert(p);
            }
            else if(op == 1 && y.count(p) == 0){
                it = y.lower_bound(p);
                leny.insert(*it - p);
                int len = *it - *(--it);
                leny.erase(leny.find(len));
                leny.insert(p - *it);
                y.insert(p);
            }
            it = lenx.end();
            ll ansx = *(--it);
            it = leny.end();
            ll ansy = *(--it);
            printf("%lld\n", ansx * ansy);
        }
    }
    return 0;
}

 

posted @ 2019-08-14 16:18  Tianwell  阅读(132)  评论(0编辑  收藏  举报