http://poj.org/problem?id=2991
题意:
有N根杆子,前后两根杆子通过一个节点连接,每个节点可以旋转一定的角度,每次给你一个操作(s,a)表示将第s与s+1之间的角度修改为a度,并且每次操作之后都需要求出第N个节点的位置。
思路:
线段树。直观的想法是这样的, 如果第s与s+1之间的角度被修改为a的话,其前面的(1-s)是不会发现改变的, 但是其后的(s+1,N)都会发生改变, 也就是说如果我们知道了s与s+1之间的角度增加了一个角度aa, 那么他后面的所有的线段的角度都要增加这个角度aa。这样我们就很容易会想到线段树的做法,成段地去更新后面的所有的线段的角度。最后要询问的终点的坐标也就是所有线段(看作向量)的和了。
代码:
#include<stdio.h> #include<string.h> #include<math.h> #include<stdlib.h> #define LL(a) ( (a)<<1 ) #define RR(a) ( (a)<<1|1 ) #define PI (4*atan(1.0)) #define eps (1e-8) const int MAXN = 10010 ; int N , C ; int len[MAXN] ; int angle[MAXN<<2] ; double x[MAXN<<2] ,y[MAXN<<2] ; int lazy[MAXN<<2] ; void up(int l ,int r, int idx){ x[idx] = x[ LL(idx) ] + x[ RR(idx) ] ; y[idx] = y[ LL(idx) ] + y[ RR(idx) ] ; } void build(int l ,int r, int idx){ lazy[idx] = angle[idx] = 0 ; if(l == r){ x[idx] = 0 ; y[idx] = len[l] ; return ; } int mid = (l + r) >> 1 ; build(l , mid , LL(idx)); build(mid+1 , r , RR(idx) ) ; up(l ,r, idx); } void down(int l ,int r, int idx){ if( lazy[idx] ){ angle[ LL(idx) ] = ( angle[ LL(idx) ] + lazy[idx] ) % 360; angle[ RR(idx) ] = ( angle[ RR(idx) ] + lazy[idx] ) % 360; double a = x[ LL(idx) ] , b = y[ LL(idx) ] ; x[ LL(idx) ] = cos( lazy[idx]/180.0*PI )*a - sin( lazy[idx]/180.0*PI )*b ; y[ LL(idx) ] = sin( lazy[idx]/180.0*PI )*a + cos( lazy[idx]/180.0*PI )*b ; a = x[ RR(idx) ] ; b = y[ RR(idx) ] ; x[ RR(idx) ] = cos( lazy[idx]/180.0*PI )*a - sin( lazy[idx]/180.0*PI )*b ; y[ RR(idx) ] = sin( lazy[idx]/180.0*PI )*a + cos( lazy[idx]/180.0*PI )*b ; lazy[ LL(idx) ] = ( lazy[ LL(idx) ] + lazy[idx] ) % 360 ; lazy[ RR(idx) ] = ( lazy[ RR(idx) ] + lazy[idx] ) % 360 ; lazy[idx] = 0 ; } } double query(int l ,int r , int idx, int x){ if(l == r) return angle[idx] ; down(l ,r , idx); int mid = (l + r) >> 1 ; if( x <= mid ) return query(l ,mid , LL(idx) ,x ) ; else return query(mid+1 , r , RR(idx) , x ) ; } void update(int l ,int r, int idx , int a, int b , int aa ){ if(l==a && r==b){ angle[idx] = ( angle[idx] + aa ) % 360 ; lazy[idx] = ( lazy[idx] + aa ) % 360 ; double xx = x[idx] , yy = y[idx] ; x[idx] = cos( aa/180.0*PI )*xx - sin( aa/180.0*PI ) * yy ; y[idx] = sin( aa/180.0*PI )*xx + cos( aa/180.0*PI ) * yy ; return ; } down(l ,r , idx) ; int mid = (l + r) >> 1; if( b<=mid ) update(l , mid ,LL(idx) , a , b , aa ); else if( mid<a ) update(mid+1, r, RR(idx) ,a , b, aa ) ; else{ update( l ,mid , LL(idx) , a, mid , aa ) ; update( mid+1, r, RR(idx) ,mid+1, b, aa ) ; } up(l ,r, idx); } void solve(){ int s, a ; for(int i=1;i<=C;i++){ scanf("%d %d",&s ,&a ); int a1 = query(1 , N , 1 ,s ) ; int a2 = query(1 , N , 1 ,s+1); int aa = (a - ( 180 + ( a2 - a1 + 360 )%360)%360 + 360 ) % 360 ; update(1 ,N ,1 , s+1, N , aa ) ; printf("%.2lf %.2lf\n",x[1] , y[1]) ; } } int main(){ bool f = true ; while(scanf("%d%d",&N,&C) == 2){ for(int i=1;i<=N;i++){ scanf("%d",&len[i]); } build(1,N,1); if( !f ) puts(""); f = false ; solve() ; } return 0 ; }