标签:线段树
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; }
标签:线段树
原文地址:http://blog.csdn.net/userluoxuan/article/details/38558963