HDOJ 1558 Segment set(并查集 + 线段判交)

来源:互联网 发布:mac豆沙色口红推荐 编辑:程序博客网 时间:2024/05/22 05:28

Segment set




Problem Description
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
110P 1.00 1.00 4.00 2.00P 1.00 -2.00 8.00 4.00Q 1P 2.00 3.00 3.00 1.00Q 1Q 3P 1.00 4.00 8.00 2.00Q 2P 3.00 3.00 6.00 -2.00Q 5
 

Sample Output
12225
题目大意:给出一些线段的起点和终点,如果两条线段相交,那么它们就属于同一个集合。对于每个query k,输出第k条线段所属的集合中有几条线段。

解题思路:如果两条线段相交,就把它们放到同一个集合里,然而如何判断两条线段是否相交呢?我也不会。。。在网上找了一份线段判交的模板,结合着并查集写出来了。。。

代码如下:

#include <algorithm>#include <cctype>#include <climits>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <map>#include <queue>#include <set>#include <stack>#include <vector>#define EPS 1e-6#define INF INT_MAX / 10#define LL long long#define MOD 100000000#define PI acos(-1.0)struct Point{    double x;    double y;};struct Line{    Point begin;    Point end;};const int maxn = 1005;int par[maxn],rank[maxn],num[maxn];Line line[maxn];void init(int n){    for(int i = 1;i <= n;i++){        par[i] = i;        rank[i] = 0;        num[i] = 1;    }}int find(int x){    return par[x] == x ? x : par[x] = find(par[x]);}void unite(int x,int y){    x = find(x);    y = find(y);    if(x == y)        return ;    if(rank[x] < rank[y]){        par[x] = y;        num[y] += num[x];        num[x] = 0;    }    else{        par[y] = x;        num[x] += num[y];        num[y] = 0;        if(rank[x] == rank[y])            rank[x]++;    }}bool onSegment(Point p,Point q,Point r){    if(q.x <= std::max(p.x,r.x) && q.x >= std::min(p.x,r.x) && q.y <= std::max(p.y,r.y) && q.y >= std::min(p.y,r.y))        return 1;    return 0;}int orientation(Point p,Point q,Point r){    int val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);    if(val == 0)        return 0;    return val > 0 ? 1 : 2;}bool doIntersect(Point p1,Point q1,Point p2,Point q2){    int o1 = orientation(p1,q1,p2);    int o2 = orientation(p1,q1,q2);    int o3 = orientation(p2,q2,p1);    int o4 = orientation(p2,q2,q1);    if(o1 != o2 && o3 != o4)        return 1;    if(o1 == 0 && onSegment(p1,p2,q1))        return 1;    if(o2 == 0 && onSegment(p1,q2,q1))        return 1;    if(o3 == 0 && onSegment(p2,p1,q2))        return 1;    if(o4 == 0 && onSegment(p2,q1,q2))        return 1;    return false;}int main(){    char opt[3];    int t,n;    scanf("%d",&t);    while(t--){        scanf("%d",&n);        init(n);        int cnt = 1;        for(int i = 0;i < n;i++){            scanf("%s",opt);            if(opt[0] == 'P'){                scanf("%lf %lf %lf %lf",&line[cnt].begin.x,&line[cnt].begin.y,&line[cnt].end.x,&line[cnt].end.y);                if(cnt > 1){                    for(int i = 1;i < cnt;i++){                        if(doIntersect(line[i].begin,line[i].end,line[cnt].begin,line[cnt].end)){                            unite(i,cnt);                        }                    }                }                cnt++;            }            if(opt[0] == 'Q'){                int k;                scanf("%d",&k);                k = find(k);                printf("%d\n",num[k]);            }        }        if(t)            printf("\n");    }    return 0;}


0 0