图片说明
源自雨巨的课程ppt
首先考虑一下静态的情况:如果给定了n个点,如何求其中优势点的个数?
要找一个优势点A,就是以A和原点O为对角点的各边平行于坐标轴的矩形中,没有其他的点。也就是说,如果不存在一个点的x和y都比A小,那么A就是优势点。
所以要想找优势点,就是要同时比较x和y的大小。
考虑x用于枚举,y用于比较:从小到大枚举x,x相同时从小到大枚举y。如果A点的y坐标>前面任意一点的y坐标,再加上A的x一定不小于前面点的x(因为这里是按照x从小到大枚举的),就可以得出A不是优势点。所以我们需要用一个变量,记录当前枚举到的点当中y的最小者。
如果把一个图中的优势点都记录下来,就可以发现,每个点的y是依次下降的。
下面回到本题
考察插入一个新点P时,如何利用已经算好的优势点,计算当前状态下的优势点?
首先,原本不是优势点的,插入P后依然不是优势点。
所以只需考虑原本的优势点
可以发现,P左边的点会决定P是否为优势点,而P会决定它右边的点是否为优势点。
首先,我们以x为第一关键字,y为第二关键字,对已经找过的优势点进行排序。这里可以使用multiset,里头存储每个点。也可以使用map,x和y分别是两个关键字,这样就能保持x从小到大天然有序。
接下来,使用lower_bound找到P应该插入的位置,如果P前面的点y值大于P的y,那么P就是优势点,P可以顺利插入。也就是说,左边最相邻的点,其y值能决定P是否有优势。
接着需要用P去过滤右边的点。如果后面点的y值大于P,那么后面的点就失去了优势,需要从multiset或map中删除。
这样就完成了动态查找优势点的过程。
最后一个小细节,不同case之间需要一个空行隔开,而最后一个case输出完成后不需要有多余的空行。
方法一:multiset,存放点的结构体类型

#include <bits/stdc++.h>
using namespace std;
typedef struct point ty;
struct point{
    int x,y;
    bool operator < (const point & a) const{
        return (x<a.x || (x==a.x && y<a.y));
    }
}a[15010];
multiset<struct point> st;
int main(){
    //freopen("text.txt","r",stdin);
    ios::sync_with_stdio;cin.tie(0);cout.tie(0);
    int T;    
    cin >> T;
    for(int k=1;k<=T;k++){
        cout << "Case #" << k <<":\n";
        st.clear();
        int n;    
        cin >> n;
        for(int i=0;i<n;i++){
            int x,y;
            cin >> x >> y;
            ty p;//定义一个点 
            p.x=x;
            p.y=y;
            multiset <ty>::iterator it = st.lower_bound(p);
            if(it==st.begin() || (--it)->y>y){//新加入一个优势点 
                st.insert(p);
                it=st.upper_bound(p);
                while(it!=st.end() && (it)->y>=y)    st.erase(it++);
            }
            cout << st.size() << "\n";
        }
        if(k<T)    cout << "\n";
    }
    return 0;
}

方法二:map,将x作为第一关键字,y作为第二关键字,二分查找时,注意查找的关键字是x

#include <bits/stdc++.h>
using namespace std;
multimap<int,int> mp;
int main(){
    //freopen("text.txt","r",stdin);
    ios::sync_with_stdio;cin.tie(0);cout.tie(0);
    int T;    
    cin >> T;
    for(int k=1;k<=T;k++){
        cout << "Case #" << k <<":\n";
        mp.clear();
        int n;    
        cin >> n;
        for(int i=0;i<n;i++){
            int x,y;
            cin >> x >> y;
            multimap <int,int>::iterator it =mp.lower_bound(x);
            if(it==mp.begin() || (--it)->second>y){//新加入一个优势点 
                it=mp.upper_bound(x);
                mp.insert({x,y});
                while(it!=mp.end() && ((it)->second)>=y)    mp.erase(it++);
            }
            cout << mp.size() << "\n";
        }
        if(k<T)    cout << "\n";
    }
    return 0;
}