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;
}