并查集+计算几何线段相交(快速排斥实验&跨立实验) HDU 1558 Segment set

时间:2023-02-10 18:20:43

Segment set

TimeLimit: 3000/1000 MS (Java/Others)    Memory Limit:32768/32768 K (Java/Others)
Total Submission(s): 5359    Accepted Submission(s): 2064

ProblemDescription

A segmentand all segments which are connected with it compose a segment set. The size ofa segment set is the number of segments in it. The problem is to find the sizeof 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 inthe plane at first, so the first command is always a P-command.

并查集+计算几何线段相交(快速排斥实验&跨立实验) HDU 1558 Segment set 

 

Output

For each Q-command, output the answer.There is a blank line between test cases.

 

 

SampleInput

1

10

P 1.001.00 4.00 2.00

P 1.00-2.00 8.00 4.00

Q 1

P 2.003.00 3.00 1.00

Q 1

Q 3

P 1.004.00 8.00 2.00

Q 2

P 3.003.00 6.00 -2.00

Q 5

 

 

SampleOutput

1

2

2

2

5

 

 

Author

LL

 

 

Source

HDU2006-12 Programming Contest

 

 

Recommend

LL

 

LL 

算法分析:

题意:给几条线段,动态输出条线段所在的集合中包含的线段的个数

算法:并查集+快速排斥实验&跨立实验(点这里) 判断两直线是否相交(相交合并即可)

代码实现:

#include<bits/stdc++.h>
using namespace std;;
#define  N 1005
int fa[N],num[N];
int find(int x)
{
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
struct point{
    double x,y;
}P1,P2,Q1,Q2;
struct Edge
{
    point a,b;
}e[N];
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;
	scanf("%d",&T);
	while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            num[i]=1;fa[i]=i;
        }
        int sum=0;
        char s[5];
        for(int i=1;i<=n;i++)
        {
            scanf("%s",s);
            if(s[0]=='P')
            {
              sum++;
               scanf("%lf%lf%lf%lf",&e[sum].a.x,&e[sum].a.y,&e[sum].b.x,&e[sum].b.y);
               for(int j=1;j<sum;j++)
               {
                   if(find(j)!=find(sum)&&Cross(e[sum].a,e[sum].b,e[j].a,e[j].b))
                   {
                       //cout<<sum<<" "<<j<<endl;
                       int r1=find(sum),r2=find(j);
                       if(r1!=r2)
                       {
                          //cout<<r1<<"    "<<r2<<endl;
                           fa[r1]=r2;
                           num[r2]+=num[r1];//注意r2才是父亲节点

                       }
                   }

               }
            }
            else
            {
                int t;
                scanf("%d",&t);
                printf("%d\n",num[find(t)]);//找他的父亲节点的集合线段数
            }
        }
        if(T)//每个测试用例要输出空行,注意最后一个样例不用输出空行
        printf("\n");
    }
    return 0;

}