hdu 1558(线段相交+并查集)

题意:给你一些操作,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;
}


你可能感兴趣的:(LCA,计算几何)