HDU 3511 Prison Break

/*
 直接复制粘贴的别人的代码
 需要形象化地理解点的加入和删除,扫描线的扫描过程
 */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<set>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn = 51111;
const double eps = 1e-8;
inline int dcmp(double x) {return (x > eps) - (x < -eps);}
inline double Sqr(double x) {return x * x;}
int LineNow, ltp, n, cnt[maxn];
struct Cir//圆
{
    int x;
    int y;
    int r;
}c[maxn];
struct Line//从左向右扫描节点
{
    int id;
    bool in;
    void Read(int id_, bool in_){id = id_, in = in_;}
    inline int GetSite()const{return c[id].x + (in ? -c[id].r : c[id].r);}
    bool operator<(const Line &b)const{return GetSite() < b.GetSite();}
}l[maxn << 1];
struct Node//从上至下排序节点
{
    int id;
    bool up;
    Node(){}
    Node(int id_, bool up_){id = id_, up = up_;}
    inline double GetSite()const
    {return c[id].y + sqrt(Sqr(c[id].r) - Sqr(LineNow - c[id].x)) * (up ? 1 : -1);}
    bool operator<(const Node &b)const
    {
        double y1 = GetSite();
        double y2 = b.GetSite();
        return dcmp(y1 - y2) ? y1 > y2 : up > b.up;
    }
};
set<Node> s;//set<>用红黑树实现,在每次插入新节点时并不是重新进行排序,而是自根开始,运用比较规则进行排序
set<Node>::iterator iti, itn;
void ReadData(int n)
{
    int i;
    for(ltp = i = 0; i < n; ++ i)
    {
        scanf("%d%d%d", &c[i].x, &c[i].y, &c[i].r);
        l[ltp ++].Read(i, true);//圆的左端点
        l[ltp ++].Read(i, false);//圆的右端点
    }
}
int MakeAns()
{
    int i, ans = 0;
    sort(l, l + ltp);//每个圆的端点按照从左到右的顺序排序
    s.clear();
    for(i = 0; i < ltp; ++ i)
    {
        LineNow = l[i].GetSite();
        if(!l[i].in)
        {
            s.erase(Node(l[i].id, true));
            s.erase(Node(l[i].id, false));
        }
        else
        {
            iti = itn = s.insert(Node(l[i].id, true)).first;
            //此时iti和itn指向插入节点的位置
            itn ++;
            if(iti == s.begin() || itn == s.end()) cnt[l[i].id] = 1;//最外层的圆
            else
            {
                iti --;
                if((*iti).id == (*itn).id) cnt[l[i].id] = cnt[(*iti).id] + 1;//相交的两个交点在同一个圆上
                else cnt[l[i].id] = max(cnt[(*iti).id], cnt[(*itn).id]);//相交的两个交点在不同的圆上
            }
            ans = max(ans, cnt[l[i].id]);
            s.insert(Node(l[i].id, false));
        }
    }
    return ans;
}
int main()
{
    while(scanf("%d", &n) != EOF)
    {
        ReadData(n);
        printf("%d\n", MakeAns());
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值