【题意】
有一个为N节的机械手,每次可以让某个关节点旋转到某一角度,问旋转操作结束之后最末端节点的坐标。
【解题方法】
当第i段与第i+1段之间的关节进行旋转时,从第i+1段到第n段都要进行旋转,类似于成段更新(成段旋转),如果把每个线段看成一个向量的话,末端的坐标等于所有向量的和。已知某个点的坐标(x,y),求逆时针旋转之后的坐标:
或
【AC code】//POJ.2991
//Crane
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=10010;
struct node{
int l,r;
double x,y;
int lazy;
}Tree[maxn<<2];
int angel[maxn];
//int input[maxn];
void init()
{
for(int i=1; i<=maxn; i++) angel[i]=180.0;
}
void Rotate(int rt,int d)
{
double x,y;
double dd;
dd=(double)d*acos(-1.0)/180.0;
x=Tree[rt].x*cos(dd)-Tree[rt].y*sin(dd);
y=Tree[rt].x*sin(dd)+Tree[rt].y*cos(dd);
Tree[rt].x=x;
Tree[rt].y=y;
}
void PushUp(int rt)
{
Tree[rt].x=Tree[rt<<1].x+Tree[rt<<1|1].x;
Tree[rt].y=Tree[rt<<1].y+Tree[rt<<1|1].y;
}
void PushDown(int rt)
{
if(Tree[rt].lazy)
{
Tree[rt*2].lazy+=Tree[rt].lazy;
Tree[rt*2+1].lazy+=Tree[rt].lazy;
Rotate(rt*2,Tree[rt].lazy);
Rotate(rt*2+1,Tree[rt].lazy);
Tree[rt].lazy=0;
}
}
void Build(int l,int r,int rt)
{
Tree[rt].l=l,Tree[rt].r=r;
Tree[rt].lazy=0;
if(l==r)
{
Tree[rt].x=0;
scanf("%lf",&Tree[rt].y);
return ;
}
int mid=(l+r)/2;
Build(l,mid,rt*2);
Build(mid+1,r,rt*2+1);
PushUp(rt);
}
void update(int L,int R,int val,int rt)
{
if(L<=Tree[rt].l&&Tree[rt].r<=R)
{
Tree[rt].lazy+=val;
Rotate(rt,val);
return ;
}
PushDown(rt);
int mid=(Tree[rt].l+Tree[rt].r)/2;
if(L<=mid) update(L,R,val,rt*2);
if(mid<R) update(L,R,val,rt*2+1);
PushUp(rt);
}
int main()
{
int n,c;
while(~scanf("%d%d",&n,&c))
{
Build(1,n,1);
init();
//puts("success");
int a,b;
for(int i=1; i<=c; i++)
{
scanf("%d%d",&a,&b);
update(a+1,n,b-angel[a],1);
angel[a]=(double)b;
printf("%.2f %.2f\n",Tree[1].x,Tree[1].y);
}
}
}