POJ 2991(线段树)

题意:有n根长度不尽相同的棍子,初始时它们首尾垂直相连,标号为1--n,第一根棍子的下端坐标为(0,0),上端坐标为(0,len[1]),其余棍子依次类推。接下来执行C此旋转,每次输入一个编号num和角度rad,使得第num根棍子和第num+1跟棍子间的逆时针角度变为rad度,求每次旋转后第n跟棍子端点的坐标。

思路:主要是是对此题如何转化为线段树的问题,这是通过对每个结点所在区间进行处理。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <stack>
#include <queue>
#include <map>
#include <algorithm>
#include <vector>
#include <cmath>
#define pi 3.141592653
using namespace std;

const int maxn = 40005;


typedef long long LL;

int N,C;
int L[maxn];
int S[maxn],A[maxn];

double vx[maxn],vy[maxn];
double ang[maxn];
double pre[maxn];

void init(int l,int r,int rt)
{
   ang[rt] = vx[rt] = 0.0;
   if(r - l == 1) {
    vy[rt] = L[l];
   }
   else{
    int lch = rt*2+1;
    int rch = rt*2+2;
    int mid = (r + l )/2;
    init(l,mid,lch);
    init(mid,r,rch);
    vy[rt] = vy[lch] + vy[rch];
   }
}

void change(int s,double a,int rt,int l,int r)
{
    if(s <= l) return ;
    else if(s < r){
        int lch = rt*2+1;
        int rch = rt*2+2;
        int mid = (l + r)/2;
        change(s,a,lch,l,mid);
        change(s,a,rch,mid,r);
        if(s <= mid) ang[rt] += a;
        double t = sin(ang[rt]);
        double c = cos(ang[rt]);
        vx[rt] = vx[lch] + (c*vx[rch] - t*vy[rch]);
        vy[rt] = vy[lch] + (t*vx[rch] + c*vy[rch]);
    }
}

void solve()
{
    init(0,N,0);
    for(int i=1;i<N;i++) pre[i] =  pi;
    for(int i=0;i<C;i++){
        int s = S[i];
        double a = A[i]/360.0*2*pi;
        change(s,a-pre[s],0,0,N);
        pre[s] = a;
        printf("%.2f %.2f
",vx[0],vy[0]);
    }
}

int main()
{
    while(scanf("%d%d",&N,&C)!=EOF){
    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]);
    }
    solve();
    }

    return 0;
}

  

原文地址:https://www.cnblogs.com/jaszzz/p/12905912.html