题意:

把手臂都各自看成一个向量,则机械手的位置正好是手臂向量之和。旋转某个关节,其实就是把关节到机械手之间的手臂向量统统旋转。

由于手臂很多,要每个向量做相同的旋转操作很费时间。这时就可以想到用线段树的优势正是可以快速地成段更新。和一般的成段更新题目没什么差别,只是通常成段替换、或者成段增加。这时候要做的是,对向量成段得做旋转变换。只要利用旋转变化矩阵即可。

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

思路:

如果我们将其中某一个线段旋转β角,那么这个线段上方的所有线段都会旋转β角,这就很类似线段树中的对区间加上一个常数的问题了,于是不妨向着线段树的思路去想。

接下来一个问题就是β角是相对于谁的,换句话说我们所谓的每个线段都会旋转β角,那么是绕谁旋转的?实际上,如果我们局限于把线段当线段看的话,那么这个旋转就会看成是绕某个定点的,这个点就是我们旋转的线段和它下面那个不动的线段的交点,再这样想下去我们就没法处理了,因为每个旋转操作所绕的定点不是唯一的,我们没办法把所有的旋转操作都统一到一起,那么我们就没办法把旋转操作叠加,这样就没法使用线段树了。

但如果换个思路的话,实际上β角还等于这个线段旋转后所在的直线和未旋转前所在的直线的夹角,而直线的夹角是可以用向量的夹角表示的,如果我们把线段看成一个向量的话那么β角就是这个向量旋转的角度。如果这么看的话,所有的旋转操作就可以统一到一起了,也可以叠加了,因为这样不会局限于绕哪个定点,只需要把向量自身旋转一下就OK。其实说到这里,我们会发现其实上一段的分析从一开始就误入歧途了,我们着眼于了“β角是相对于谁的”,因为相对的东西是不可能统一到一起的,参考系不一样结果就不一样,所以我们要想把每个线段的旋转操作统一到一起,就要去看这些旋转操作改变了哪些绝对的量,而向量就是一个绝对的量,它并不参考与其他的东西,只由这个线段自身的状态决定。

又扯远了,还是分析下怎么实现吧。前面说了,如果把线段看成向量的话,我们每次的旋转操作就可以看成是对区间上的所有点加上一个值(向量的旋转角),那么剩下的问题有两个:第一,也是最重要的,我们这样记录能不能每次方便地求出终点的位置?第二,题目中给出的是每次设定的两个线段的夹角,我们能不能方便的将其转化成相对于以前的状态旋转了多少角度?

对于第一个问题,我们既然有了每个线段的向量,那么我们只要把这些向量求和,最终所指的位置就是终点,因此我们只要维护好向量的区间和就可以了。对于第二个问题,我们可以用一个数组degree[i]表示第i个向量和第i-1一个向量当前的夹角,这样就有了当前的状态,每次读入操作后就会方便的得到相当于进行旋转多少角度的操作了,然后再更新一下degree[i]即可。并且我们每读入一个操作只会影响一个degree[]的值,不会影响到其他的degree[]。

总而言之,我们要把每个线段看成一个向量,并维护这些向量的区间和,同时要实现对区间中每个元素都加上一个值这一操作。

  1. #include <cstdio>
  2. #include <cmath>
  3.  
  4. #define LSon(x) ((x) << 1)
  5. #define RSon(x) ((x) << 1 | 1)
  6.  
  7. const int MAXN = 10002;
  8. const int ROOT = 1;
  9. const double PI = acos(-1.0);
  10. const double EPS = 1e-8;
  11.  
  12. struct Seg {
  13. double x, y;
  14. int flag;
  15. int degree;
  16. };
  17.  
  18. void Rotate(Seg& node, int degree);
  19.  
  20. struct SegTree {
  21. Seg node[MAXN << 2];
  22. void Update(int pos) {
  23. node[pos].x = node[LSon(pos)].x + node[RSon(pos)].x;
  24. node[pos].y = node[LSon(pos)].y + node[RSon(pos)].y;
  25. }
  26. void Build(int l, int r, int pos) {
  27. node[pos].x = node[pos].y = 0;
  28. node[pos].flag = 0;
  29. node[pos].degree = 0;
  30. if (l == r) {
  31. scanf("%lf", &node[pos].y);
  32. return;
  33. }
  34. int m = l + r >> 1;
  35. Build(l, m, LSon(pos));
  36. Build(m + 1, r, RSon(pos));
  37. Update(pos);
  38. }
  39. void Push(int pos) {
  40. Seg& father = node[pos];
  41. Seg& lson = node[LSon(pos)];
  42. Seg& rson = node[RSon(pos)];
  43. if (father.flag) {
  44. Rotate(lson, father.flag);
  45. Rotate(rson, father.flag);
  46. lson.flag += father.flag;
  47. rson.flag += father.flag;
  48. father.flag = 0;
  49. }
  50. }
  51. void Modify(int l, int r, int pos, int x, int y, int z) {
  52. if (x <= l && r <= y) {
  53. Rotate(node[pos], z);
  54. node[pos].flag += z;
  55. return;
  56. }
  57. Push(pos);
  58. int m = l + r >> 1;
  59. if (x <= m) Modify(l, m, LSon(pos), x, y, z);
  60. if (y > m) Modify(m + 1, r, RSon(pos), x, y, z);
  61. Update(pos);
  62. }
  63. int Query(int l, int r, int pos, int x) {
  64. if (l == r) return node[pos].degree;
  65. Push(pos);
  66. int m = l + r >> 1;
  67. if (x <= m) return Query(l, m, LSon(pos), x);
  68. else return Query(m + 1, r, RSon(pos), x);
  69. }
  70. };
  71.  
  72. int n, c;
  73. int s, a;
  74.  
  75. SegTree tree;
  76.  
  77. double GetRad(int x);
  78.  
  79. int main() {
  80. bool first = true;
  81. while (scanf("%d%d", &n, &c) != EOF) {
  82. tree.Build(0, n - 1, ROOT);
  83. printf("%s", first ? first = false, "" : "\n");
  84. for (int i = 0; i < c; i++) {
  85. scanf("%d%d", &s, &a);
  86. //由于题目是逆时针转的,我的计算是顺时针,要加上180度,将后面的棒看成依然在Y轴,所以要减去后一个的角度
  87. int degree = tree.Query(0, n - 1, ROOT, s - 1) + 180 + a -
  88. tree.Query(0, n - 1, ROOT, s);
  89. tree.Modify(0, n - 1, ROOT, s, n - 1, degree);
  90. printf("%.2lf %.2lf\n", tree.node[ROOT].x + EPS, tree.node[ROOT].y + EPS);
  91. }
  92. }
  93.  
  94. return 0;
  95. }
  96.  
  97. double GetRad(int x) {
  98. return x * PI / 180;
  99. }
  100.  
  101. void Rotate(Seg& node, int degree) {
  102. double rad = GetRad(degree);
  103. double x = node.x; double y = node.y;
  104. node.x = x * cos(rad) + y * -sin(rad);
  105. node.y = x * sin(rad) + y * cos(rad);
  106. node.degree = (node.degree + degree) % 360;
  107. }

POJ 2991–Crane【线段树+几何】的更多相关文章

  1. [poj 2991]Crane[线段树表示向量之和,而非数量]

    题意: 起重机的机械臂, 由n段组成, 对某一些连接点进行旋转, 询问每次操作后的末端坐标. 思路: 由于旋转会影响到该点之后所有线段的角度, 因此容易想到用线段树记录角度, 成段更新. (但是不是每 ...

  2. POJ 2991 Crane(线段树+计算几何)

    POJ 2991 Crane 题目链接 题意:给定一个垂直的挖掘机臂.有n段,如今每次操作能够旋转一个位置,把[s, s + 1]专程a度,每次旋转后要输出第n个位置的坐标 思路:线段树.把每一段当成 ...

  3. POJ.2299 Ultra-QuickSort (线段树 单点更新 区间求和 逆序对 离散化)

    POJ.2299 Ultra-QuickSort (线段树 单点更新 区间求和 逆序对 离散化) 题意分析 前置技能 线段树求逆序对 离散化 线段树求逆序对已经说过了,具体方法请看这里 离散化 有些数 ...

  4. Buy Tickets POJ - 2828 思维+线段树

    Buy Tickets POJ - 2828 思维+线段树 题意 是说有n个人买票,但是呢这n个人都会去插队,问最后的队列是什么情况.插队的输入是两个数,第一个是前面有多少人,第二个是这个人的编号,最 ...

  5. (中等) POJ 2991 Crane , 几何+线段树。

    Description ACM has bought a new crane (crane -- jeřáb) . The crane consists of n segments of variou ...

  6. POJ 2991 Crane(线段树)

    Crane Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7687   Accepted: 2075   Special J ...

  7. POJ 2991 Crane (线段树)

    题目链接 Description ACM has bought a new crane (crane -- jeřáb) . The crane consists of n segments of v ...

  8. POJ - 2991 Crane (段树+计算几何)

    Description ACM has bought a new crane (crane -- jeřáb) . The crane consists of n segments of variou ...

  9. poj 3264(线段树)

    http://poj.org/problem?id=3264 初学线段可以做的水题,也是线段树的基础运用.也是我的第一个线段树的题. 题意:在区间范围内的最大值减去最小值 思路:线段树记录下每个区间内 ...

随机推荐

  1. Linux学习笔记<五>

    管道命令(pipe) 1.把一个命令的输出作为另一个命令的输入 ls -al /etc | less 2.选取命令:cut和grep cut命令可以将一段消息的某段切出来. -d接分隔符,-f是取出第 ...

  2. Oracle修改字段类型方法总结

    有一个表名为tb,字段段名为name,数据类型nchar(20). 1.假设字段数据为空,则不管改为什么字段类型,可以直接执行:alter table tb modify (name nvarchar ...

  3. 2016百度之星 初赛2B ACEF

    做了1001 1003 1005 1006 看题:http://bestcoder.hdu.edu.cn/contests/contest_show.php?cid=702 交题:http://acm ...

  4. hdu2005第几天?

    Problem Description 给定一个日期,输出这个日期是该年的第几天.   Input 输入数据有多组,每组占一行,数据格式为YYYY/MM/DD组成,具体参见sample input , ...

  5. php打印中文乱码

    php文档的文本格式都设置成 utf-8 格式 在代码中添加 header("content-type:text/html; charset=utf-8");

  6. 如何让两个div在同一行显示?一个float搞定

    最近在学习div和css,遇到了一些问题也解决了很多以前以为很难搞定的问题.比如:如何让两个div显示在同一行呢?(不是用table表格,table对SE不太友好)其实,<div> 是一个 ...

  7. Java Native Interface 五 JNI里的多线程与JNI方法的注册

    本文是<The Java Native Interface Programmer's Guide and Specification>读书笔记 JNI里的多线程 在本地方法里写有关多线程的 ...

  8. 关于robotframework,app,appium的xpath定位问题及常用方法

    关于类似的帖子好像很多,但是没有找到具体能帮我解决问题的办法.还是自己深究了好久才基本知道app上面的xpath定位和web上的不同点: 先放一个图: A,先说说不用xpath的场景,一般是用于存在i ...

  9. html5 json的新用法

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. powershell使用

    主要语法点: -match -notmatch -replace -join -split -and -or -xor -not ! +.-.*./.% =.+=.-=.*=./=.%= -eq.-n ...