P6327 题解:区间加,其实是在转圈
区间加,求区间 和。只存 不够,还得带上 。
题目链接。每次给一段数都加上 ,或者查询这一段的 ,角度按弧度计算。
只存正弦和无法更新: 还依赖 ,所以节点要把两者一起存。
把区间加法看成旋转
每个角度对应向量 。加上 ,由两角和公式:
对整个区间求和,记 、,就得到合向量的旋转:
合并孩子时,、 分别相加,不需要区间长度。
懒标记只记角度增量
连续旋转 、,等于旋转 ,标记直接相加。下传给两个孩子后,清空父标记。
代码
#include <cmath>
struct Node { double s = 0, c = 0; long long lazy = 0;};
void apply(Node& node, long long d) { double sn = std::sin(d), cs = std::cos(d); double s = node.s, c = node.c; node.s = s * cs + c * sn; node.c = c * cs - s * sn; node.lazy += d;}
Node merge(Node left, Node right) { return {left.s + right.s, left.c + right.c, 0};}更新两项时都要使用旧的 、,不能先覆盖 node.s,再拿新值算 node.c。查询输出按题目要求保留一位小数;累计角度用 long long,和与三角函数使用 double。
建树 ,单次修改、查询 ,空间 。
本文原发表于洛谷专栏。