Segment set

A segment and all segments which are connected with it compose a segment set. The size of a segment set is the number of segments in it. The problem is to find the size of some segment set.

Input
In the first line there is an integer t - the number of test case. For each test case in first line there is an integer n (n<=1000) - the number of commands.

There are two different commands described in different format shown below:

P x1 y1 x2 y2 - paint a segment whose coordinates of the two endpoints are (x1,y1),(x2,y2).
Q k - query the size of the segment set which contains the k-th segment.

k is between 1 and the number of segments in the moment. There is no segment in the plane at first, so the first command is always a P-command.
Output
For each Q-command, output the answer. There is a blank line between test cases.
Sample Input
1
10
P 1.00 1.00 4.00 2.00
P 1.00 -2.00 8.00 4.00
Q 1
P 2.00 3.00 3.00 1.00
Q 1
Q 3
P 1.00 4.00 8.00 2.00
Q 2
P 3.00 3.00 6.00 -2.00
Q 5
Sample Output
1
2
2
2
5

题意:增加一条线段,如果和已有的线段相交,则把他们加入到一个集合中,对于每个查询,输出这条线段所在集合的元素个数
思路:快速排斥跨立实验判断相交,计数并查集维护集合合并

快速排斥
就是初步的判断一下,两条线段是不是相交,以两条线段为对角线的矩形,如果不相交的话,那么两条线段一定不可能相交。

bool kspc(node p,node q){          //快速排斥试验
	if(min(p.a.x,p.b.x)>max(q.a.x,q.b.x)) return false;//线段p的最左端大于线段q的最右端,必不相交
	if(max(p.a.x,p.b.x)<min(q.a.x,q.b.x)) return false;//线段p的最右端小于线段q的最左端,必不相交
	if(min(p.a.y,p.b.y)>max(q.a.y,q.b.y)) return false;//线段p的最低点高于线段q的最高点,必不相交
	if(max(p.a.y,p.b.y)<min(q.a.y,q.b.y)) return false;//线段p的最高点低于线段q的最低点,必不相交
	return true;     //通过快速排斥试验,可能相交(需要跨立试验进一步判断)
} 

跨立试验
如果两线段相交,则两线段必然相互跨立对方。

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=1005;
const double eps=1e-8;
struct point{          //点 
	double x,y;
};
struct node{           //线段 
	point a,b;
}l[maxn];
int pre[maxn],sum[maxn];
bool kspc(node p,node q){          //快速排斥实验
	if(min(p.a.x,p.b.x)>max(q.a.x,q.b.x)) return false;
	if(max(p.a.x,p.b.x)<min(q.a.x,q.b.x)) return false;
	if(min(p.a.y,p.b.y)>max(q.a.y,q.b.y)) return false;
	if(max(p.a.y,p.b.y)<min(q.a.y,q.b.y)) return false;
	return true;
} 
double cc(point a,point b,point c){ //叉乘 
	double x1=b.x-a.x;
	double y1=b.y-a.y;
	double x2=c.x-a.x;
	double y2=c.y-a.y;
	return x1*y2-x2*y1;
} 
bool kl(node p,node q){  //跨立实验 
	if((cc(p.a,p.b,q.a)*cc(p.a,p.b,q.b)<0||fabs(cc(p.a,p.b,q.a)*cc(p.a,p.b,q.b)-0)<eps)&&(cc(q.a,q.b,p.a)*cc(q.a,q.b,p.b)<0||fabs(cc(q.a,q.b,p.a)*cc(q.a,q.b,p.b)-0)<eps))
	return true;
	return false;
} 
void init(int n){         //初始化 
	for(int i=1;i<=n;i++){
		pre[i]=i;
		sum[i]=1;
	}
}
int find(int x){
	return x==pre[x]?x:pre[x]=find(pre[x]);
} 
void merge(int x,int y){
	int fx=find(x);
	int fy=find(y);
	if(fx!=fy){
		pre[fx]=fy;
		sum[fy]+=sum[fx];
		sum[fx]=0;
	}
}
int main(){
	int t,n;
	char c;
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		init(n);
		int num=0;
		for(int i=0;i<n;i++){
			getchar();
			scanf("%c",&c);
			if(c=='P'){
				num++;
				scanf("%lf%lf%lf%lf",&l[num].a.x,&l[num].a.y,&l[num].b.x,&l[num].b.y);
				for(int j=1;j<num;j++){
					if(kspc(l[j],l[num])&&kl(l[j],l[num])) merge(j,num);
				}
			}
			else{
				int x;
				scanf("%d",&x);
				printf("%d\n",sum[find(x)]);
			}
		} 
		if(t!=0) printf("\n");
	}	
	return 0;
}