HDU-1558,Segment set,并查集+线段相交模拟

Segment set

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 5033    Accepted Submission(s): 1931


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
 
  
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


并查集知识和模板见我的另一篇文章(用到了按数量合并)传送门

代码用了很多c++的封装技巧(类函数和运算符重载);重要内容都在代码上 注释了;

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#define mem(x) memset(x,0,sizeof(x))
using namespace std;
const int N=1e3+1;

struct point{//点类
    double x,y;
    void reset(double a,double b){x=a;y=b;}
    /* void show(){
        cout<<"("<<x<<','<<y<<')'<<' ';
    } */
};

struct seg{
    point p1,p2;
    double k;
    void reset(double a,double b,double c,double d){
        p1.reset(a,b);p2.reset(c,d);
        k=dy(p1,p2)/dx(p1,p2);
    }
    double dx(point &a,point &b){
        return a.x-b.x;
    }
    double dy(point &a,point &b){
        return a.y-b.y;
    }
    double fun(point &a){ //将点带入直线,类似于线性规划的解法
        return dy(a,p1)-k*dx(a,p1);
    }
    /* void show(){
        p1.show();p2.show(); cout<<k<<endl;;
    } */
};
bool is_connected(seg & a,seg &b){  //点在直线的两侧(一个点直线上也行)说明线段与直线相交,再反过来验证一遍;
        //cout<<b.fun(a.p1)<<' '<<b.fun(a.p2)<<' '<<a.fun(b.p1)<<' '<<a.fun(b.p2)<<endl;
        return (b.fun(a.p1)*b.fun(a.p2)<=0)&&(a.fun(b.p1)*a.fun(b.p2)<=0);
}
bool operator == (const point & a,const point &b){
    return (a.x==b.x)&&(a.y==b.y);
}

bool operator == (const seg & a,const seg &b){
    return (a.p1==b.p1)&&(a.p2==b.p2);
}

int fa[N];seg sg[N];

int f_r(int x){
    int root=x,t;
    while(fa[root]>0) root=fa[root];
    while(x!=root){
        t=fa[x]; //保留父亲节点
        fa[x]=root;
        x=t;
    }
    return x;
}

bool join(int r1,int r2){        //并集
    if(r1==r2) return false;
    if(fa[r1]<fa[r2]){
        fa[r1]+=fa[r2]; //更新 后来发现这里写错了r1,r2是根,而fa[root]才是集合的个数的负值;
        fa[r2]=r1;  //合并
    }
    else{
        fa[r2]+=fa[r1];
        fa[r1]=r2;
    }
    return true;
}

/* void print(int n){cout<<"the fa is ";for(int i=1;i<=n;i++)cout<<fa[i]<<' ';cout<<endl;} */
int main(){
    //freopen("in.txt","r",stdin);
    int T;cin>>T;
    while(T-- >0){
        int n,t,cur=0;char op[2];double x1,y1,x2,y2;memset(fa,-1,sizeof(fa));
        cin>>n;
        while(n-- >0){
            scanf("%s",op);
            if(op[0]=='P'){
                cin>>x1>>y1>>x2>>y2;              //cout<<op<<' '<<x1<<' '<<y1<<"  "<<x2<<' '<<y2<<endl;
                cur++;
                sg[cur].reset(x1,y1,x2,y2);       //sg[cur].show();
                for(int i=1;i<cur;i++){           //cout<<endl<<"i="<<i<<"cur="<<cur<<endl;
                    if(sg[i]==sg[cur]) {cur--;break;}          //我这里特意判断了重复的线段
                    if (is_connected(sg[i],sg[cur]))
                    join(f_r(i),f_r(cur));                 //并集
                }
                //print(cur);
            }
            else if(op[0]=='Q'){
                cin>>t; //cout<<op<<' '<<t<<endl;
                cout<<(-fa[f_r(t)])<<endl;          //输出查询结点的根的绝对值即可;
            }
        }
        if(T!=0)cout<<endl;
    }
    return 0;
}


猜你喜欢

转载自blog.csdn.net/zhonglong_lin/article/details/75564767