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