题意:对每一个提问,求出第K条线段所在集合的线段数。
所以相交的线段属于同一个集合
分析:几何+并查集
View Code
#include<iostream>
#include<algorithm>
#include<string>
#include<math.h>
#define MAXN 1000+10
using namespace std;
struct Point
{
double x,y;
};
struct seg
{
Point a,b;
}se[MAXN];
int n,m,f[MAXN],r[MAXN];
void init()
{
for(int i=0;i<m;i++)
{
f[i]=i;
r[i]=1;
}
n=1;
}
float multiply(Point p1,Point p2,Point p0)
{
return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}
//a(x1,y1),b(x2,y2)
//x1*y2-x2*y1
//确定两条线段是否相交
int intersect(seg u,seg v)
{
return( (max(u.a.x,u.b.x)>=min(v.a.x,v.b.x))&& //u中最右的点是否在v最左的点的右边
(max(v.a.x,v.b.x)>=min(u.a.x,u.b.x))&& //v中最右的点是否在u最左的点的右边
//判断这两条线段在水平层面上是否可能相交
(max(u.a.y,u.b.y)>=min(v.a.y,v.b.y))&& //u中最上的点是否在v最下的点的上边
(max(v.a.y,v.b.y)>=min(u.a.y,u.b.y))&& //v中最上的点是否在u最下的点的上边
//判断这两条线段在垂直层面上是否可能相交
(multiply(v.a,u.b,u.a)*multiply(u.b,v.b,u.a)>=0)&&
//判断v.a,v.b是否分布在u.b两侧(或线上)
(multiply(u.a,v.b,v.a)*multiply(v.b,u.b,v.a)>=0));
//判断u.a,u.b是否分布在v.a两侧(或线上)
}
int find(int x)
{
if(x==f[x])
return f[x];
f[x]=find(f[x]);
return f[x];
}
void Union(int x,int y)
{
int a=find(x);
int b=find(y);
if(a==b) return ;
f[a]=b;
r[b]+=r[a];
r[a]=0;
}
void addSeg()
{
for(int i=1;i<n;i++)
{
if(intersect(se[i],se[n])!=0)
{
// cout<<se[i].a.x<<' '<<se[i].a.y<<' '<<se[i].b.x<<' '<<se[i].b.y<<endl;
// cout<<se[n].a.x<<' '<<se[n].a.y<<' '<<se[n].b.x<<' '<<se[n].b.y<<endl;
// cout<<i<<"and"<<n<<endl;
Union(i,n);
}
}
n++;
}
int main()
{
int T,cas=0;
char str[2];
scanf("%d",&T);
while(T--)
{
if(cas)
puts("");
cas++;
scanf("%d",&m);
init();
int k;
while(m--)
{
scanf("%s",str);
if(str[0]=='P')
{
scanf("%lf %lf %lf %lf",&se[n].a.x,&se[n].a.y,&se[n].b.x,&se[n].b.y);
addSeg();
}
else {
scanf("%d",&k);
printf("%d\n",r[find(k)]);
}
}
}
return 0;
}