Description
Input
Output
Sample Input
2 1 10 5 1 90 3 2 5 5 5 1 270 2 90
Sample Output
5.00 10.00 -10.00 5.00 -5.00 10.00
解题思路:
这题涉及到了几何问题。首先得知道一个点(x0,y0)绕原点逆时针旋转n角度后的坐标为:x = x0 * cosn - y0 * sinn, y = x0 * sinn + y0 * cosn。在此不证明。
把吊车的每个旋转关节都当做是原点,则吊车最初状态的每节车臂坐标为(0,li),li为每节的长度。只需要将最终状态的每节车臂的坐标加起来,就得到了车臂末尾真正的坐标。
线段树进行更新的时候需要注意:当一个旋转关节旋转,后面的每节车臂都要旋转相同的角度,也就是要进行旋转角度和坐标的区间更新。
AC代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1
#define PI acos(-1.0)
const int maxn = 10010;
double len[maxn];
struct node
{
double x, y; //用结构体记录每节车臂的坐标和旋转角度
int angl;
}p[maxn << 2];
void Func(int rt, double rad) // 求旋转后的坐标
{
double s = p[rt].x, t = p[rt].y;
p[rt].x = s * cos(rad) - t * sin(rad);
p[rt].y = s * sin(rad) + t * cos(rad);
}
void PushUp(int rt) //坐标相加
{
p[rt].x = p[rt << 1].x + p[rt << 1 | 1].x;
p[rt].y = p[rt << 1].y + p[rt << 1 | 1].y;
}
void PushDown(int rt) // 向下更新子叶的坐标与旋转角度
{
if (p[rt].angl)
{
p[rt << 1].angl += p[rt].angl;
p[rt << 1 | 1].angl += p[rt].angl;
double rad = p[rt].angl * PI / 180;
p[rt].angl = 0;
Func(rt << 1, rad);
Func(rt << 1 | 1, rad);
}
}
void build(int l, int r, int rt)
{
p[rt].angl = 0;
if(l == r)
{
p[rt].y = len[l];
p[rt].x = 0;
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
}
void update(int cur, int a, int l, int r, int rt) // 对车臂的旋转角度和坐标进行更新
{
if (l == r)
{
double rad = a * PI / 180;
Func(rt, rad);
return ;
}
PushDown(rt);
int m = (l + r) >> 1;
if (cur <= m)
{
double rad = a * PI / 180;
update(cur, a, lson);
Func(rt << 1 | 1, rad); //右子叶的坐标都要进行更新
p[rt << 1 | 1].angl += a; //右子叶的旋转角度都要进行更新
}
else
update(cur, a, rson);
PushUp(rt);
}
int main()
{
int n, c, s, a, degree[maxn];
bool First = true;
while(scanf("%d%d", &n, &c) != EOF)
{
memset(degree,0,sizeof(degree));
if(First)
{
First = false;
}
else
printf("\n");
for(int i = 1; i <= n; i++)
scanf("%lf", &len[i]);
build(1, n, 1);
while(c--)
{
scanf("%d%d", &s, &a);
int delta = a - 180 - degree[s + 1]; // 求得是多旋转的角度
degree[s + 1] = a - 180; // 求得是旋转的角度
update(s + 1, delta, 1, n, 1);
printf("%.2f %.2f\n", p[1].x, p[1].y);
}
}
return 0;
}