题意:
直角坐标系上有N条相连线段(序号分别为1,2,3...N)
最底层线段的起点为原点
每条线段的初始放置状态平行于y轴方向
输入每个线段的长度,以及对序号i线段进行的操作角度a
a的含义为使i与i+1之间角度为a
输出进行给定操作后线段端点的坐标。
思路:
每次对序号i转动改变的是编号为 1到i 以及 i+1到N两个线段集合的位置关系,需要对两者状态进行高效的动态维护。
提取出集合中需要维护的参数并列出关系式即可写出对应的线段树算法。
#include <stdio.h>
#include <math.h>
#define MAX_N 10010
#define MAX_C 10010
#define ST_SIZE ((1 << 15) - 1)
#define M_PI 3.1415926
int N, C;
int L[MAX_N];
int S[MAX_C], A[MAX_N];
double vx[ST_SIZE], vy[ST_SIZE]; // position for node
double ang[ST_SIZE];
double prv[MAX_N];
void init(int now, int l, int r)
{
ang[now] = vx[now] = 0.0;
if(r - l == 1)
vy[now] = L[l];
else
{
int chl = 2*now + 1, chr = 2*now + 2;
int mid = (l+r)/2;
init(chl, l, mid);
init(chr, mid, r);
vy[now] = vy[chl]+vy[chr];
}
}
void change(int s, double a, int v, int l, int r)
{
if(s<=l)
return;
else if(s < r)
{
int chl = v*2+1;
int chr = v*2+2;
int m = (l + r)/2;
change(s, a, chl, l, m);
change(s, a, chr, m, r);
if(s <= m)
ang[v] += a;
double s = sin(ang[v]), c = cos(ang[v]);
vx[v] = vx[chl] + (c*vx[chr] - s*vy[chr]);
vy[v] = vy[chl] + (s*vx[chr] + c*vy[chr]);
}
}
int main()
{
int first = 0;
while(scanf("%d %d", &N, &C) == 2)
{
if(first)
printf("\n");
else
first = 1;
for (int i = 0; i < N; ++i)
{
scanf("%d", &L[i]);
prv[i] = M_PI;
}
init(0, 0, N);
for (int i = 0; i < C; ++i)
{
int s;
double a;
scanf("%d %lf", &s, &a);
a = a/360.0 * 2 * M_PI;
change(s, a - prv[s], 0, 0, N);
prv[s] = a;
printf("%.2f %.2f\n", vx[0], vy[0]);
}
}
}
结果是WA,可能哪些细节没有处理好