这题哪里是考并查集啊……分明在考几何………………几何无能者抄之……
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
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 |
#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两侧, 由向量叉积的性质, ( Q0P0 x Q0Q1) * (Q0Q1 x Q0P1) > 0. 同理, 若Q0Q1跨立P0P1, 则P0Q0与P0Q1分别位于P0P1两侧, 所以 ( P0Q0 x P0P1) * ( P0Q1 x P0P1) > 0. 考虑到线段的端点可能在另一条线段上的情况, 上面的 > 可以改为 >= . 实现细节请看across().
假装我看懂了这个见鬼的跨立……让我想到军训了……