poj-2991
来源:互联网 发布:照片审核处理工具 mac 编辑:程序博客网 时间:2024/06/06 23:16
// 1260K 985MS C++#include <stdio.h>#include <string.h>#include <math.h>const int MAX = 10010;const double PI = acos(-1.0);double getrad(int x) { return x * PI / 180;}struct TreeNode { int left; int right; double X; double Y; int angle; int lazyRotation;};typedef struct TreeNode TreeNode;TreeNode tree[MAX<<2];int curDegree[MAX];void buildTree(int pos, int begin, int end) { TreeNode & curNode = tree[pos]; curNode.left = begin; curNode.right = end; curNode.X = 0; curNode.Y = 0; curNode.angle = 0; curNode.lazyRotation = 0; if (begin == end) { return; } else { int mid = (begin + end)>>1; buildTree(pos<<1, begin, mid); buildTree(pos<<1|1, mid+1, end); }}int segmentsNum;int opNum;void Rotate(double &dx, double &dy, double rad){ double x = dx, y = dy; dx = x * cos(rad) - y * sin(rad); dy = x * sin(rad) + y * cos(rad);}void pushDown(int pos) { TreeNode & curNode = tree[pos]; int curX = curNode.X; int curY = curNode.Y; int curLazyRotation = curNode.lazyRotation; if (curLazyRotation && (curNode.left < curNode.right)) { // need some rotation TreeNode & leftNode = tree[pos<<1]; TreeNode & rightNode = tree[pos<<1|1]; leftNode.angle += curLazyRotation; rightNode.angle += curLazyRotation; leftNode.angle %= 360; rightNode.angle %= 360; Rotate(leftNode.X, leftNode.Y, getrad(curLazyRotation)); // leftNode.X += curX; // leftNode.Y += curY; Rotate(rightNode.X, rightNode.Y, getrad(curLazyRotation)); // rightNode.X += leftNode.X; // rightNode.Y += leftNode.Y; leftNode.lazyRotation += curLazyRotation; rightNode.lazyRotation += curLazyRotation; leftNode.lazyRotation %= 360; rightNode.lazyRotation %= 360; curNode.lazyRotation = 0; }}void pushUp(int pos) { if (pos == 1) { return; } int parentPos = pos>>1; TreeNode & curNode = tree[parentPos]; // printf("pushUp %d %d\n", curNode.left, curNode.right); TreeNode & leftNode = tree[parentPos<<1]; TreeNode & rightNode = tree[parentPos<<1|1]; curNode.X = leftNode.X + rightNode.X; curNode.Y = leftNode.Y + rightNode.Y;}void updateSegmentWithY(int pos, int rangeLeft, int rangeRight, int Y) { TreeNode & curNode = tree[pos]; int left = curNode.left; int right = curNode.right; // printf("updateSegmentWithX %d %d %d %d\n", rangeLeft, rangeRight, left, right); if (left == rangeLeft && rangeRight == right) { curNode.Y = Y; } else { int mid = (left + right)>>1; if (rangeRight <= mid) { updateSegmentWithY(pos<<1, rangeLeft, rangeRight, Y); } else if (rangeLeft > mid) { updateSegmentWithY(pos<<1|1, rangeLeft, rangeRight, Y); } } pushUp(pos);}void update(int pos, int rangeLeft, int rangeRight, int rotationAngle) { TreeNode & curNode = tree[pos]; int left = curNode.left; int right = curNode.right; // printf("update %d %d %d %d %d\n", rangeLeft, rangeRight, left, right, rotationAngle); if (rangeLeft <= left && right <= rangeRight) { curNode.lazyRotation += rotationAngle; curNode.lazyRotation %= 360; // printf("Rotate %lf %lf %d\n", curNode.X, curNode.Y,rotationAngle); Rotate(curNode.X, curNode.Y, getrad(rotationAngle)); // printf("after Rotate %lf %lf %d\n", curNode.X, curNode.Y,rotationAngle); pushUp(pos); return; } pushDown(pos); int mid = (left + right)>>1; if (rangeRight <= mid) { update(pos<<1, rangeLeft, rangeRight, rotationAngle); } else if (rangeLeft <= mid && rangeRight > mid) { update(pos<<1, rangeLeft, mid, rotationAngle); update(pos<<1|1, mid+1, rangeRight, rotationAngle); } else if (rangeLeft > mid) { update(pos<<1|1, rangeLeft, rangeRight, rotationAngle); } pushUp(pos);}int main() { // FILE * in = fopen("/local/POJ/2991In", "r"); while(scanf("%d %d", &segmentsNum, &opNum) != EOF) { buildTree(1, 1, segmentsNum); for (int i = 0; i < segmentsNum - 1; i++) { curDegree[i] = 180; // init all 180, from s -> s+1, counterclock } int Y = 0; for (int i = 1; i <= segmentsNum; i++) { int length; scanf("%d", &length); Y += length; updateSegmentWithY(1, i, i, length); } // printf("begin\n"); for (int i = 0; i < opNum; i++) { int segmentId; int newDegree; scanf("%d %d", &segmentId, &newDegree); int oldDegree = curDegree[segmentId-1]; if (newDegree != oldDegree) { update(1, segmentId +1, segmentsNum, newDegree - oldDegree); curDegree[segmentId-1] = newDegree; } printf("%.2lf %.2lf\n", tree[1].X, tree[1].Y); } printf("\n"); } // fclose(in);}
一道几何和线段树结合的题,让已经把几何丢差不多的我痛不欲生,这道题其实能看出大致的思路,但是真正细化到实现的时候却又一头雾水了。
后来搜发现对着道题也是众解纷纭,这里用了一种我觉得最为简便的方法,
一共有N段segment, 并且一开始都是垂直向上立着的,
首先,要把线段树构建起来,
根区间是 [1, N], 表示全部的segments,每个节点都保存这样的信息:
X,Y: 此节点代表的segments的集合的终点相对于起点的坐标
lazyRotation: 此节点代表的segments的集合起点与终点的连线相对于x轴的角度, 因为转动而变化的角度值(也是一个重要的lazy tag, 上面代码里的angle其实没用).
这样要求最后一个segment的绝对坐标,
只需求出 线段树的根区间节点的X,Y即可(根区间的起点是(0,0), 因此X,Y就是相对于(0,0)坐标原点的坐标, 直接就是绝对坐标)。
重要的操作和要点有这几个:
<1> 因为题目的转动输入 是以 将某两个segment i 和 i+1之间的逆时针夹角变化为某个角度来表现的,因为需要搞一个数组,记录当前每个 segment间夹角的值,
这样在有输入时,可以根据此次变化成的角度 D1 和 原来的 segment间夹角 D2来比较。 D1-D2就是此次转动所 实际转动的角度(逆时针方向).
<2> 记住要初始化线段树每个节点的X和Y, 因为初始状态是垂直的,因此,X都为0, 而 Y则是segment的长度:
比如, 有两个segmengt 1 和 2, 长度分别为 10 和 5, 那么线段树共有3个端点,其XY分别为:
[1, 2] (X = 0, Y = 15)
[1 , 1] (X = 0, Y =10) [2, 2](X = 0, Y = 5)
<2> update 更新线段树的某一段, 因为题目的实际情况, 如果转动第i个segment(注意题的输入是把第i-1和第i个segment之间的夹角变化),其实从第i到最后一个segment N都是被转动的(因为是一个crane,这也是我们可以用lazyTag来进行区间更新的原因), 因此每次更新的区间是(i, N),然后就是标准的线段树更新流程,
如果当前操作的线段树节点区间 被 [i, N]完全覆盖,那么就将这一段进行旋转,更新X 和 Y(直接抄了一个旋转的函数), 以及将 lazyTag加上 此次转动的角度, 然后 pushUp(很重要,因为父区间的X和Y等于其左右孩子区间的X 和 Y的相加,因为我们定义的X和Y是相对的,所以可以这样), 否则 pushDown,检查区间相交情况,然后递归处理,最后,还要pushUp, 一次update只有一次pushUp, 但必须pushUp。
<3> pushUp, 在子区间的X和Y因为旋转变化以后,要将其向上将变化传递到父区间, 父区间的X 和 Y 分别等于 两个子区间的X 和Y的和,
因为我们定义的是相对于这段区间起点的X和Y,所以这个等式成立:
比如, segment1的 起点坐标是 (0, 0) 终点坐标是 (5, 0)(也是相对于(0,0)的相对坐标), 而segment2的起点坐标是 (5,0), 终点坐标是(5,5), 那么 其X , Y也就是(5,5)相对于(5,0)的坐标是 (0,5),
这样, segment1+2组成的区间的终点坐标相对于起点坐标就是 (5,0) + (0, 5) = (5,5)(相对于(0,0)的相对坐标)。可以将X和Y理解为此区间内子区间X和Y的区间和。
<4>pushDown,这一步,就是将lazyTag代表的旋转角度下发到两个子区间去执行,每个子区间分别根据这次的lazyTag的旋转角度旋转自己的X和Y,同时继承累加lazyTag的旋转角度(可以加完 % 一下 360, 这样能避免累加角度过大),最后父区间的laztTag = 0表示没有被lazy的旋转操作。
这道题的精髓就在于 相对坐标的应用 ,可以大大简化题,而旋转则可以体现出线段树的区间批量操作以及lazyTag的高效.
- poj 2991
- POJ 2991
- poj-2991
- POJ 2991
- poj 2991
- POJ 2991
- poj 2991 Crane
- POJ 2991 - Crane
- POJ 2991 Crane
- poj 2991-Crane
- POJ 2991 Crane
- poj 2991(区间更新)
- poj 2991crane
- POJ 2991 线段树
- 挑战 POJ.2991 Crane
- POJ 2991 Crane
- poj 2991 Crane
- POJ 2991:Crane
- PHP 导出Excel
- 转汇集各种 webservice工厂,快递,ip,天气,身份证,手机,翻译,火车时刻,股票,邮编,二维码,公交,ISBN,ICP 查询接口 API
- 简单的Boost::asio 高性能C/S服务器模型
- STL vector中的get_allocator方法(27)
- Windows多点触控模拟
- poj-2991
- Unity3D-关于协程的一些东西
- HDOJ 2544 最短路 Floyf+Dijistra算法
- android-resource-remover的研究和实验
- magento定制修改
- sort函数
- ESB
- HMM topology and transition modeling
- 输入字符串和字节数,截取子串(串中含有中文字符)