/*
直接复制粘贴的别人的代码
需要形象化地理解点的加入和删除,扫描线的扫描过程
*/
#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;
}
HDU 3511 Prison Break
最新推荐文章于 2017-10-15 11:25:00 发布