C - Segment set

C - Segment set
Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

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

     
     
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


题意是给你n次操作,如果输入了P 那么就输入一条线段的两个端点坐标 x1,y1,x2,y2。 如果为 Q操作,那么 Q num 表示和num这条线段直接或间接相交的有多少条线段。


对于这道题来说并查集的应用并不多,只用单独开一个nu[i]来记录以i为父亲的节点有多少个,在插入的时候更新即可,问题在于判断相交,至今对判断方法不太清楚,借用了别人的函数。


#include"iostream"
#include"cstring"
#include"cstdio"
#include"cmath"
#include"algorithm"

#define eps 1e-10

using namespace std;

struct Point
{
    double x,y;
};

struct Line
{
    Point a,b;
}line[1005];

int fa[1005];
int nu[1005];

void init()
{
    for(int i = 0;i < 1005;i++) fa[i] = i;
    for(int i = 0;i < 1005;i++) nu[i] = 1;
}

int find_fa(int x)
{
    if(x == fa[x]) return x;
    fa[x] = find_fa(fa[x]);
    return fa[x];
}

void add(int x,int y)
{
    int fx = find_fa(x);
    int fy = find_fa(y);
    if(fx == fy) return;
    fa[fx] = fy;
    nu[fy] += nu[fx];
    nu[fx] = 0;
}

double multiply(Point p1,Point p2,Point p0)
{
    return((p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y));
}

int intersect(Line u,Line v)
{
    return( (max(u.a.x,u.b.x)>=min(v.a.x,v.b.x))&&
    (max(v.a.x,v.b.x)>=min(u.a.x,u.b.x))&&
    (max(u.a.y,u.b.y)>=min(v.a.y,v.b.y))&&
    (max(v.a.y,v.b.y)>=min(u.a.y,u.b.y))&&
    (multiply(v.a,u.b,u.a)*multiply(u.b,v.b,u.a)>=0)&&
    (multiply(u.a,v.b,v.a)*multiply(v.b,u.b,v.a)>=0));
}

int main(void)
{
    int T;
    scanf("%d",&T);
    for(int cas = 1;cas <= T;cas++)
    {
        init();
        int n;
        int num = 0;
        scanf("%d",&n);
        for(int i = 1;i <= n;i++)
        {
            char typ;
            cin >> typ;
            if(typ == 'P')
            {
                num++;
                scanf("%lf %lf %lf %lf",&line[num].a.x,&line[num].a.y,&line[num].b.x,&line[num].b.y);
                for(int j = 1;j < num;j++)
                {
                    if(intersect(line[j],line[num]) != 0)
                    {
                        add(j,num);
                    }
                }
            }
            if(typ == 'Q')
            {
                int xx;
                scanf("%d",&xx);
                int aa = find_fa(xx);
                printf("%d\n",nu[aa]);
            }
        }
        if(cas != T) printf("\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值