题目大意
题目链接。
思路
- 将每一段视作一个向量。
- 由起重机性质: 当将第
i
i
i个向量旋转
A
o
A^o
Ao,则所有的序号
>
=
i
>=i
>=i的向量也旋转
A
o
A^o
Ao。
- 将向量
i
(
v
x
,
v
u
)
i(v_x, v_u)
i(vx,vu)旋转
A
o
A^o
Ao的公式可以这样表示
#define PI acos(-1) double ang = -A * / 360 * 2 * PI; // A是逆时针,加-号代表顺时针旋转 double x = vx[i]; double y = vy[i]; vx[i] = x * cos(ang) - y * sin(ang); vy[i] = x * sin(ang) + y * cos(ang);
- 最后所求就是所有向量相加。
- 一个坑点:题目中是将第i条线段和第i+1条线段的角度直接变为A,因此需要旋转序号大于等于i+1的向量A-pre[i]度(其中pre[i]是以前两条线段的角度)
线段树维护
此题涉及到区间所有向量的同一角度旋转,使用普通数组维护会超时,因此我们使用线段树维护,一个节点维护该区间所有向量的和,最后我们的所求结果就是根节点所维护的向量和。关于线段树讲解可以见此博客。
- 代码:
#include<stdio.h>
#include<math.h>
#define PI acos(-1)
using namespace std;
int N, C;
const int MAXN = 10000 + 5;
int L[MAXN];
int pre[MAXN];
int s, a;
struct Node
{
// (vx, vy):该区间内所有向量之和
double vx;
double vy;
int start; //该区间其实向量id
int end; //该区间结束向量id
// 区间是前开后闭的[start, id)
double degree; //该区间内所有向量需要旋转的角度,还没有传递给子节点
}segment_tree[4 * MAXN];
void build_tree(int start, int end, int index)
{
segment_tree[index].start = start;
segment_tree[index].end = end;
segment_tree[index].degree = 0;
if(start == end - 1)
{
segment_tree[index].vx = 0;
segment_tree[index].vy = 1.0 * L[start];
return;
}
int mid = (start + end) >> 1;
int left = (index << 1) + 1;
int right = (index << 1) + 2;
build_tree(start, mid, left);
build_tree(mid, end, right);
segment_tree[index].vx = segment_tree[left].vx + segment_tree[right].vx;
segment_tree[index].vy = segment_tree[left].vy + segment_tree[right].vy;
return;
}
void rotate_degree(double &x, double &y, double degree)
{
double tmp_x = x;
double tmp_y = y;
x = tmp_x * cos(degree) - tmp_y * sin(degree);
y = tmp_x * sin(degree) + tmp_y * cos(degree);
}
void push_down(int index)
{
if(segment_tree[index].degree != 0)
{
double ang = segment_tree[index].degree;
int left = (index << 1) + 1;
int right = (index << 1) + 2;
rotate_degree(segment_tree[left].vx, segment_tree[left].vy, ang);
rotate_degree(segment_tree[right].vx, segment_tree[right].vy, ang);
segment_tree[left].degree += ang;
segment_tree[right].degree += ang;
segment_tree[index].degree = 0;
}
}
void update_seg(int s, double ang, int index)
{
if(segment_tree[index].end <= s)
return;
if(s <= segment_tree[index].start)
{
segment_tree[index].degree += ang;
rotate_degree(segment_tree[index].vx, segment_tree[index].vy, ang);
return;
}
int left = (index << 1) + 1;
int right = (index << 1) + 2;
push_down(index);
update_seg(s, ang, left);
update_seg(s, ang, right);
segment_tree[index].vx = segment_tree[left].vx + segment_tree[right].vx;
segment_tree[index].vy = segment_tree[left].vy + segment_tree[right].vy;
return;
}
int main()
{
while(scanf("%d%d", &N, &C)!=EOF)
{
for(int i=0; i<N; i++)
{
scanf("%d", &L[i]);
pre[i] = 180;
}
build_tree(0, N, 0);
for(int i=0; i<C; i++)
{
scanf("%d%d", &s, &a);
int r = a - pre[s-1];
pre[s-1] = a;
double ang = r * 1.0/ 360 *2 * PI;
update_seg(s, ang, 0); //旋转序号大于等于s的向量
printf("%.2f %.2f\n", segment_tree[0].vx, segment_tree[0].vy);
}
}
return 0;
}