hdu 1558 Segment set 5.1.4

来源:互联网 发布:网络开关 编辑:程序博客网 时间:2024/05/29 13:48

这题哪里是考并查集啊……分明在考几何………………几何无能者抄之……

Segment set

Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 45 Accepted Submission(s): 19 
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
 

#include <iostream>using namespace std;#define SIZE 1001#define MAX(a,b) (a>b?a:b)  #define MIN(a,b) (a<b?a:b) struct point{       double x,y;       }line[SIZE][2];int p[SIZE];inline bool across(int i,int j){       double x1,x2,x3,y1,y2,y3;       x1=line[i][0].x-line[j][0].x;       y1=line[i][0].y-line[j][0].y;       x2=line[j][1].x-line[j][0].x;       y2=line[j][1].y-line[j][0].y;       x3=line[i][1].x-line[j][0].x;       y3=line[i][1].y-line[j][0].y;       return (x1*y2-x2*y1)*(x2*y3-x3*y2)>=0;}inline bool isRecIntersect(int i,int j){       return MAX(line[i][0].x,line[i][1].x)>=MIN(line[j][0].x,line[j][1].x) &&             MAX(line[i][0].y,line[i][1].y)>=MIN(line[j][0].y,line[j][1].y);       }inline bool isIntersect(int i,int j){return isRecIntersect(i,j)&&isRecIntersect(j,i)&&across(i,j)&&across(j,i);}    int find(int x){    if(p[x]<0)//p[x]less than 0 mean's it is root and connected to -p[x] segment.    //else mean it is not root and root is p[x].    return x;    else    return p[x]=find(p[x]);}            void merge(int x,int y){     int fx=find(x),fy=find(y);     int ff=p[fx]+p[fy];     if(fx!=fy&&isIntersect(x,y))     {         if(p[fx]>p[fy])         {             p[fx]=fy;             p[fy]=ff;         }         else         {             p[fy]=fx;             p[fx]=ff;         }     }}int main(){    int cas;    cin>>cas;    while(cas--)    {        memset(p,-1,sizeof(p));        int c;        int i;        int n=1;        cin>>c;        while(c--)        {            char cmd[2];            cin>>cmd;            if(cmd[0]=='P')            {                cin>>line[n][0].x>>line[n][0].y>>line[n][1].x>>line[n][1].y;                for(i=1;i<n;i++)                    merge(i,n);                n++;            }            else            {                cin>>i;                cout<<-p[find(i)]<<endl;            }        }        if(cas)//if not the last cas            puts("");    }//    system("pause");    return 0;}   

粘贴党:

可以用向量来判断线段是否相交:

    ①快速排斥试验: 设以线段P0P1为对角线的矩形为R, 以Q0Q1为对角线的矩形为T, 若R与T不相交, 则显然这两条线段不相交. 这个过程可以用包围盒判别来做, 细节请看isRecIntersect();

    ②跨立试验: 若两线段相交, 则它们必然互相跨立对方. 若P0P1跨立Q0Q1, 则Q0P0与Q0P1分别位于Q0Q1两侧, 由向量叉积的性质, ( Q0Px Q0Q1) * (Q0Q1 x Q0P1) > 0. 同理, 若Q0Q1跨立P0P1, 则P0Q0与P0Q1分别位于P0P1两侧, 所以 ( P0Q0 x  P0P1) * ( P0Qx  P0P1) > 0. 考虑到线段的端点可能在另一条线段上的情况, 上面的 > 可以改为 >= . 实现细节请看across().


话说这题快速排斥试验有没有好像是一样的……

假装我看懂了这个见鬼的跨立……让我想到军训了……