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>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#define N 1010
const int mm = 1000000007;
using namespace std;
struct line
{
double x1, y1, x2, y2;
bool fun(line l)
{
double xx, yy; //两直线的交点
double k1, k2; //两直线的斜率
if (fabs(this->x1-this->x2) < 1e-7 && fabs(l.x1-l.x2) < 1e-7) //都垂直于y轴
{
if (fabs(l.x1-this->x1) < 1e-7) return true;
return false;
}
else if (fabs(this->x1-this->x2) < 1e-7) //
{
if ((this->x1-l.x1)*(this->x1-l.x2) > -1e-8) return false;
k2 = (l.y1-l.y2)/(l.x1-l.x2);
xx = this->x1;
yy = k2*(xx-l.x1) + l.y1;
if ((this->y1-yy)*(yy-this->y2) >= -1e-8) return true;
return false;
}
else if (fabs(l.x1-l.x2) < 1e-7) //l垂直于y轴
{
if ((l.x1-this->x1)*(l.x1-this->x2) > -1e-8) return false;
xx = l.x1;
yy = k1*(xx-this->x1) + this->y1;
if ((l.y1-yy)*(yy-l.y2) >= 0) return true;
return false;
}
else
{
k1 = (this->y1-this->y2)/(this->x1-this->x2);
k2 = (l.y1-l.y2)/(l.x1-l.x2);
if (fabs(k1-k2) < 1e-7) return false; // 两直线是不是平行
xx = (k1*this->x1-this->y1-k2*l.x1+l.y1)/(k1-k2);
yy = k2*(xx-l.x1) + l.y1;
if ((this->x1-xx)*(xx-this->x2)>=0 && (l.x1-xx)*(xx-l.x2)>=0) return true;//两直线的交点是不是在两条连段上
return false;
}
}
}ll[N];
int father[N], num[N];
int find(int x)
{
if (x == father[x]) return father[x];
int t = father[x];
father[x] = find(father[x]);
num[x] += num[t];
return father[x];
}
void union_set(int x, int y)
{
int xx = find(x);
int yy = find(y);
if (xx != yy)
{
father[xx] = yy;
num[yy] += num[xx];
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("1.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int i, j, T, n, cnt, t;
char c;
cin >> T;
while(T--)
{
cin >> n;
cnt = 1;
for (i = 0; i <= n; i++)
{
father[i] = i;
num[i] = 1;
}
while(n--)
{
cin >> c;
if (c == 'P')
{
cin >> ll[cnt].x1 >> ll[cnt].y1 >> ll[cnt].x2 >> ll[cnt].y2;
for (i = 1; i < cnt; i++)
if (ll[cnt].fun(ll[i]))
union_set(i, cnt);
cnt++;
}
else
{
cin >> t;
t = find(t);
cout << num[t] << endl;
}
}
if (T) cout << endl;
}
return 0;
}