题意:给你一些操作,P后边输入四个值,分别代表一条线段的起点、终点坐标,当输入Q时,后边输入一个整形值K,输出第k条线段所在的集合中包含的线段的个数。
解题思路:线段相交+并查集,sum[i]表示i所在的线段集合中,i为根节点的线段总数。在合并时可以更新。
#include<stdio.h>
#include<iostream>
using namespace std;
struct point
{
double x,y;
};
struct edge
{
point a;
point b;
}e[1010];
int fa[1010],sum[1010];
int find(int x)
{
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void Union(int x,int y)
{
int fx = find(x);
int fy = find(y);
if(fx != fy)
{
fa[fx]=fy;
sum[fy] += sum[fx];
}
}
double xmult(point a,point b,point c) //大于零代表a,b,c左转
{
return (b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x);
}
bool OnSegment(point a,point b,point c) //a,b,c共线时有效
{
return c.x>=min(a.x,b.x)&&c.x<=max(a.x,b.x)&&c.y>=min(a.y,b.y)&&c.y<=max(a.y,b.y);
}
bool Cross(point a,point b,point c,point d) //判断ab 与cd是否相交
{
double d1,d2,d3,d4;
d1 = xmult(c,d,a);
d2 = xmult(c,d,b);
d3 = xmult(a,b,c);
d4 = xmult(a,b,d);
if(d1 * d2 < 0 && d3 * d4 < 0) return 1;
else if(d1 == 0 && OnSegment(c,d,a)) return 1;
else if(d2 == 0 && OnSegment(c,d,b)) return 1;
else if(d3 == 0 && OnSegment(a,b,c)) return 1;
else if(d4 == 0 && OnSegment(a,b,d)) return 1;
return 0;
}
int main()
{
int t,n,k,tmp,i,j;
char s[10];
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
k = 0;
for(int i = 1; i <= n; i++)
sum[i] = 1, fa[i] = i;
for(int i=1;i<=n;i++)
{
scanf("%s",s);
if(s[0]=='P')
{
k++;
scanf("%lf%lf%lf%lf",&e[k].a.x,&e[k].a.y,&e[k].b.x,&e[k].b.y);
for(int j=1;j<k;j++)
if(Cross(e[k].a,e[k].b,e[j].a,e[j].b))
Union(k,j);
}
else if(s[0]=='Q')
{
scanf("%d",&tmp);
printf("%d\n",sum[find(tmp)]);
}
}
if(t) printf("\n");
}
return 0;
}