POJ 2991 Crane(线段树)
【题目链接】 http://poj.org/problem?id=2991
【题目大意】
给出一条竖直线,由很多线段组成,
每次可以把中间某个节点的位置逆时针转动一定角度,求每次转动之后这条线终点位置。
【题解】
用线段树维护线段的角度和向量有:
vx[x]=vx[lson]+cosα*vx[rson]-sinα*vy[rson]
vy[x]=vy[lson]+sinα*vx[rson]+cosα*vy[rson]
对被影响的区段,更新其角度。
【代码】
#include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; const double PI=acos(-1.0); const int ST_SIZE=(1<<15)-1; const int MAX_C=10010,MAX_N=10010; int Fi,N,C,L[MAX_N],S[MAX_C],A[MAX_C]; double vx[ST_SIZE],vy[ST_SIZE],ang[ST_SIZE],prv[MAX_N]; void build(int x,int l,int r){ ang[x]=vx[x]=0.0; if(r-l==1){vy[x]=L[l];return;} build(x<<1|1,l,(l+r)>>1); build(x+1<<1,(l+r)>>1,r); vy[x]=vy[x<<1|1]+vy[x+1<<1]; } void change(int s,double a,int x,int l,int r){ if(s<=l)return; else if(s<r){ change(s,a,x<<1|1,l,l+r>>1); change(s,a,(x+1)<<1,l+r>>1,r); if(s<<1<=l+r)ang[x]+=a; double s=sin(ang[x]),c=cos(ang[x]); vx[x]=vx[x<<1|1]+c*vx[x+1<<1]-s*vy[x+1<<1]; vy[x]=vy[x<<1|1]+s*vx[x+1<<1]+c*vy[x+1<<1]; } } int main(){ while(~scanf("%d%d",&N,&C)){ if(Fi++)puts(""); for(int i=0;i<N;i++)scanf("%d",&L[i]); for(int i=0;i<C;i++)scanf("%d%d",&S[i],&A[i]); build(0,0,N); for(int i=1;i<N;i++)prv[i]=PI; for(int i=0;i<C;i++){ int s=S[i]; double a=A[i]/360.0*2*PI; change(s,a-prv[s],0,0,N); prv[s]=a; printf("%.2f %.2f\n",vx[0],vy[0]); } }return 0; }
愿你出走半生,归来仍是少年