POJ 2991 - Crane

来源:互联网 发布:查重软件免费 编辑:程序博客网 时间:2024/05/19 02:02

Advanced Data Structures :: Segment Tree

 

Description

有一个机械臂,想象它以直角坐标系的原点为轴,一节连着一节,最末端为机械手。

你可以旋转任意一个关节,改变机械手的位置。

(有点像《cut the rope》中的机械臂?没错,就是那么个玩意)

而现在要做的就正是这么一件事。

告诉你机械臂每节手臂的长度,不停得去操作它(旋转某个关节)。

请求出每次操作之后机械手的位置。


Type

Advanced Data Structures :: Segment Tree


Analysis

刚开始看可能会质疑,很奇怪,这题和线段树有很什么关系。

其实这题是计算几何和线段树的合体。

我们把手臂都各自看成一个向量。
则机械手的位置正好是手臂向量之和。

旋转某个关节,其实就是把关节到机械手之间的手臂向量统统旋转。
由于手臂很多,要每个向量做相同的旋转操作很费时间。
这时候我们就可以想到用线段树的优势正是可以快速地成段更新。

其实和一般的成段更新题目没什么差别,只是我们通常只是成段替换、或者成段增加。
这时候要做的是,对向量成段得做旋转变换。
只要利用旋转变化矩阵即可。

要注意,从第 s 节手臂开始到机械手要旋转的角度,和第 s - 1 节手臂的角度有关。
因此我们还要记录每个手臂的角度,并且去Query得到它们,才能知道我们要旋转的角度。

Solution
#include <cstdio>#include <cmath>#define LSon(x) ((x) << 1)#define RSon(x) ((x) << 1 | 1)const int MAXN = 10002;const int ROOT = 1;const double PI = acos(-1.0);const double EPS = 1e-8;struct Seg {    double x, y;    int flag;    int degree;};void Rotate(Seg& node, int degree);struct SegTree {    Seg node[MAXN << 2];    void Update(int pos) {        node[pos].x = node[LSon(pos)].x + node[RSon(pos)].x;        node[pos].y = node[LSon(pos)].y + node[RSon(pos)].y;    }    void Build(int l, int r, int pos) {        node[pos].x = node[pos].y = 0;        node[pos].flag = 0;        node[pos].degree = 0;        if (l == r) {            scanf("%lf", &node[pos].y);            return;        }        int m = l + r >> 1;        Build(l, m, LSon(pos));        Build(m + 1, r, RSon(pos));        Update(pos);    }    void Push(int pos) {        Seg& father = node[pos];        Seg& lson = node[LSon(pos)];        Seg& rson = node[RSon(pos)];        if (father.flag) {            Rotate(lson, father.flag);            Rotate(rson, father.flag);            lson.flag += father.flag;            rson.flag += father.flag;            father.flag = 0;        }    }    void Modify(int l, int r, int pos, int x, int y, int z) {        if (x <= l && r <= y) {            Rotate(node[pos], z);            node[pos].flag += z;            return;        }        Push(pos);        int m = l + r >> 1;        if (x <= m) Modify(l, m, LSon(pos), x, y, z);        if (y > m) Modify(m + 1, r, RSon(pos), x, y, z);        Update(pos);    }    int Query(int l, int r, int pos, int x) {        if (l == r) return node[pos].degree;        Push(pos);        int m = l + r >> 1;        if (x <= m) return Query(l, m, LSon(pos), x);        else return Query(m + 1, r, RSon(pos), x);    }};int n, c;int s, a;SegTree tree;double GetRad(int x);int main() {    bool first = true;    while (scanf("%d%d", &n, &c) != EOF) {        tree.Build(0, n - 1, ROOT);           printf("%s", first ? first = false, "" : "\n");        for (int i = 0; i < c; i++) {            scanf("%d%d", &s, &a);               int degree = tree.Query(0, n - 1, ROOT, s - 1) + 180 + a -                tree.Query(0, n - 1, ROOT, s);            tree.Modify(0, n - 1, ROOT, s, n - 1, degree);            printf("%.2lf %.2lf\n", tree.node[ROOT].x + EPS, tree.node[ROOT].y + EPS);        }    }    return 0;}double GetRad(int x) {    return x * PI / 180;}void Rotate(Seg& node, int degree) {    double rad = GetRad(degree);    double x = node.x; double y = node.y;    node.x = x * cos(rad) + y * -sin(rad);    node.y = x * sin(rad) + y * cos(rad);    node.degree = (node.degree + degree) % 360;}




原创粉丝点击