[poj 2991]Crane[线段树表示向量之和,而非数量]
题意:
起重机的机械臂, 由n段组成, 对某一些连接点进行旋转, 询问每次操作后的末端坐标.
思路:
由于旋转会影响到该点之后所有线段的角度, 因此容易想到用线段树记录角度, 成段更新. (但是不是每一次操作都要询问一次么? 那么懒惰标记还有用么? 如果使用懒惰标记, 将一些线段视为整体, 那么这些线段岂不是又要用一个线段树记录一段区间的总长? 树状数组亦可...)
将向量视为数量整体加和, 融入到线段树的操作中, 就可以避免角度和坐标分离的麻烦事..
旋转角度与坐标的关系:
根据位移向量绕原点旋转的表达式, 借助三角函数公式, 可推得矩阵形式的向量旋转公式.
[ x1 ] = [ cos a sin a ] [ x0 ]
[ y1 ] [ -sin a cos a] [ y0 ]
思维上的不足:
对线段树的求和理念理解不深, 只是想到了角度的加和, 殊不知向量本身也可以加和, 而且"和向量"与"分向量"的关系是层层细分下去的.
有了这样的思维框架, 就不难照顾好 sx, sy, sd 这三个数组了. 因为要表示一个"位移向量", 使用这三个参数是自然的.
#include<cstdio>
#include<cmath>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1 ///把所有的区间看做等效的一条线段
///旋转的时候认为是只旋转宏观的!中间的细节是不考虑的 using namespace std;
const int mm=11111;
int sd[mm<<2],degree[mm];
double sx[mm<<2],sy[mm<<2];
void rotate(int rt,int sd)
{
double d=sd*asin(1.0)/90.0;//degrees in rad
double x=cos(d)*sx[rt]-sin(d)*sy[rt];
double y=sin(d)*sx[rt]+cos(d)*sy[rt];
sx[rt]=x,sy[rt]=y;// rotate the sub-tree as a whole~!
}
void pushdown(int rt)//!
{//认为每一条线段都是一个[偏移量], 最终是加和嘛
rotate(rt<<1,sd[rt]);
rotate(rt<<1|1,sd[rt]);
sd[rt<<1]+=sd[rt];//将标记落在下一层
sd[rt<<1|1]+=sd[rt];
sd[rt]=0;//清除本层标记
}
void pushup(int rt)
{
sx[rt]=sx[rt<<1]+sx[rt<<1|1];
sy[rt]=sy[rt<<1]+sy[rt<<1|1];
}
void build(int l,int r,int rt)
{
sd[rt]=0;//segment delta degree (must as a whole)
if(l==r)
{
scanf("%lf",&sy[rt]);
sx[rt]=0;//segment coordinates
return;
}
int m=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);//only coordinates
}
void updata(int p,int d,int l,int r,int rt)
{
if(p<l)//if this sub-tree is completely in the rorated range, rotate.
{
rotate(rt,d);
sd[rt]+=d;
return;
}
if(sd[rt])pushdown(rt);//修正儿子的delta degree
int m=(l+r)>>1;
if(p<m)updata(p,d,lson);//如果[涉及]左儿子,就更新
updata(p,d,rson);///[一定][涉及]右儿子!
pushup(rt);///再更新总体的坐标
}
int main()
{
int i,j,n,m,flag=0;
while(~scanf("%d%d",&n,&m))
{
if(flag)puts("");else flag=1;//判断第一个
build(1,n,1);
for(i=0;i<n;++i)degree[i]=180;//degree after ith segment
while(m--)
{
scanf("%d%d",&i,&j);
updata(i,j-degree[i],1,n,1);//(index, delta degree, tree)
degree[i]=j;
printf("%.2lf %.2lf\n",fabs(sx[1])<1e-8?0:sx[1],fabs(sy[1])<1e-8?0:sy[1]);
}//output root's coordinates, caution: precision
}
return 0;
}
[poj 2991]Crane[线段树表示向量之和,而非数量]的更多相关文章
- POJ 2991 Crane(线段树+计算几何)
POJ 2991 Crane 题目链接 题意:给定一个垂直的挖掘机臂.有n段,如今每次操作能够旋转一个位置,把[s, s + 1]专程a度,每次旋转后要输出第n个位置的坐标 思路:线段树.把每一段当成 ...
- POJ 2991–Crane【线段树+几何】
题意: 把手臂都各自看成一个向量,则机械手的位置正好是手臂向量之和.旋转某个关节,其实就是把关节到机械手之间的手臂向量统统旋转. 由于手臂很多,要每个向量做相同的旋转操作很费时间.这时就可以想到用线段 ...
- POJ - 2991 Crane (段树+计算几何)
Description ACM has bought a new crane (crane -- jeřáb) . The crane consists of n segments of variou ...
- (中等) POJ 2991 Crane , 几何+线段树。
Description ACM has bought a new crane (crane -- jeřáb) . The crane consists of n segments of variou ...
- POJ 2991 Crane(线段树)
Crane Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 7687 Accepted: 2075 Special J ...
- POJ 2991 Crane (线段树)
题目链接 Description ACM has bought a new crane (crane -- jeřáb) . The crane consists of n segments of v ...
- POJ 2991 Crane
线段树+计算几何,区间更新,区间求和,向量旋转. /* *********************************************** Author :Zhou Zhentao Ema ...
- AC日记——Crane poj 2991
POJ - 2991 思路: 向量旋转: 代码: #include <cmath> #include <cstdio> #include <cstring> #in ...
- POJ 1177 Picture(线段树 扫描线 离散化 求矩形并面积)
题目原网址:http://poj.org/problem?id=1177 题目中文翻译: 解题思路: 总体思路: 1.沿X轴离散化建树 2.按Y值从小到大排序平行与X轴的边,然后顺序处理 如果遇到矩形 ...
随机推荐
- hdu2492 Ping pong
hdu2492 Ping pong 题意:一群乒乓爱好者居住在一条直线上,如果两个人想打比赛需要一个裁判,裁判的 位置 必须在两者之间 ,裁判的能力也必须不大于 参赛者最大的,不小于参赛者最小的 白皮 ...
- MFC网页访问的实现示例
本示例使用MFC 类CInternetSession 建立连接,使用 CHttpFile读取内容. 首先,建立一个MFC对话框项目,界面如下: 1. 添加头文件: #include <afxin ...
- 经典排序算法 - 基数排序Radix sort
经典排序算法 - 基数排序Radix sort 原理类似桶排序,这里总是须要10个桶,多次使用 首先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,临时忽视十位数 比如 待排序数组[ ...
- 学习算法-基数排序(radix sort)卡片分类(card sort) C++数组实现
基数排序称为卡片分类,这是一个比较早的时间越多,排名方法. 现代计算机出现之前,它已被用于排序老式打孔卡. 说下基数排序的思想.前面我有写一个桶式排序,基数排序的思想是桶式排序的推广. 桶式排序:ht ...
- Canvas上绘制几何图形
重要的类自定义View组件要重写View组件的onDraw(Canvase)方法,接下来是在该 Canvas上绘制大量的几何图形,点.直线.弧.圆.椭圆.文字.矩形.多边形.曲线.圆角矩形,等各种形状 ...
- javascript 精典案例分析一览
1.[优雅代码]深入浅出 妙用Javascript中apply.call.bind http://www.cnblogs.com/coco1s/p/4833199.html 2.1.0.1 ionic ...
- SRM 582 Div II Level Two SpaceWarDiv2
题目来源:http://community.topcoder.com/stat?c=problem_statement&pm=12556 #include <iostream> # ...
- Swift - 动态添加删除TableView的单元格(以及内部元件)
在Swift开发中,我们有时需要动态的添加或删除列表的单元格. 比如我们做一个消息提醒页面,默认页面只显示两个单元格.当点击第二个单元格(时间标签)时,下面会再添加一个单元格放置日期选择控件(同时新增 ...
- ASP.NET - cookie
下面是写cookie HttpCookie cookie = new HttpCookie("Info");//定义cookie对象以及名为Info的项 DateTime dt ...
- 发掘ListBox的潜力(二):鼠标拖放插入点提示
鼠标拖放插入点提示 鼠标拖放是Windows常见的操作,比如拷贝文件就可用拖放方式进行.在我们编写的应用程序中,有时为了方便用户操作需要支持鼠标拖放.对于大部分的VCL控件只要鼠标将DragMode设 ...