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.
![](https://i-blog.csdnimg.cn/blog_migrate/986d9125246970a42423cd75c7449bf2.jpeg)
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.
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 <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;
}