Crane
题目大意:
有n根木棍,第i跟长度为
a
i
a_i
ai,最开始他们由下而上拼接在一起,有m次操作,每次操作中给出整数
S
i
S_i
Si和
A
i
A_i
Ai,要求更改第
S
i
S_i
Si与第
S
i
+
1
S_i+1
Si+1根之间至
A
i
A_i
Ai°,每次操作后输出最后一个木棍端点的坐标(设第一根木棍的端点为原点)。
这题中夹角的定义为从i逆时针到i+1根木棍走的度数。
记录每个区间的向量。
最开始想的是如果第i个和第i+1根之间旋转了了,那么第i根后面的也都旋转了,我就修改了每个最小的区间,然后往回更新,如果这样操作,每次修改的时间复杂度为
n
l
o
g
n
nlogn
nlogn所以TLE了。
加个lazy tag就行了
关于向量旋转的公式的推导:
设红色为
∠
A
∠A
∠A,蓝色为
∠
B
∠B
∠B向量长为R
初始向量为与x轴正向夹角小的,设其为
(
x
0
,
y
0
)
(x_0,y_0)
(x0,y0)
旋转后的向量设为
(
x
1
,
y
1
)
(x_1,y_1)
(x1,y1)
则可得
c
o
s
A
=
x
0
R
cosA=\frac{x_0}{R}
cosA=Rx0,
s
i
n
A
=
y
0
R
sinA=\frac{y_0}{R}
sinA=Ry0
c
o
s
(
A
+
B
)
=
x
1
R
cos(A+B)=\frac{x_1}{R}
cos(A+B)=Rx1,
s
i
n
(
A
+
B
)
=
y
1
R
sin(A+B)=\frac{y_1}{R}
sin(A+B)=Ry1
∵
c
o
s
(
A
+
B
)
=
c
o
s
A
c
o
s
B
−
s
i
n
A
s
i
n
B
cos(A+B)=cosAcosB-sinAsinB
cos(A+B)=cosAcosB−sinAsinB
∴
x
1
R
=
x
0
R
∗
c
o
s
B
−
y
0
R
∗
s
i
n
B
\frac{x_1}{R}=\frac{x_0}{R}*cosB-\frac{y_0}{R}*sinB
Rx1=Rx0∗cosB−Ry0∗sinB
∴
x
1
=
x
0
∗
c
o
s
B
−
y
0
∗
s
i
n
B
x_1=x_0*cosB-y_0*sinB
x1=x0∗cosB−y0∗sinB
同理
y
1
=
y
0
∗
c
o
s
B
+
x
0
∗
s
i
n
B
y_1=y_0*cosB+x_0*sinB
y1=y0∗cosB+x0∗sinB
卡我一晚上的点:
pushdown的时候,用的是
l
a
z
y
r
t
lazy_{rt}
lazyrt来更新两个子节点,而不是更新完后的
l
a
z
y
r
t
∗
2
lazy_{rt*2}
lazyrt∗2和
l
a
z
y
r
t
∗
2
+
1
lazy_{rt*2+1}
lazyrt∗2+1来更新他们自己,想一想下就能明白
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const double pi = acos(-1.0);
const int maxn = 1e5 + 10;
struct node
{
double x, y;
int lazy;
}tree[4 * maxn];
int deg[maxn];
void pushup(int rt)
{
tree[rt].x = tree[rt * 2].x + tree[rt * 2 + 1].x;
tree[rt].y = tree[rt * 2].y + tree[rt * 2 + 1].y;
}
void build(int rt, int l, int r)
{
tree[rt].lazy = 0;
if (l == r)
{
int temp;
scanf("%lf", &tree[rt].y);
tree[rt].x = 0;
return;
}
int mid = (l + r) / 2;
build(rt * 2, l, mid);
build(rt * 2 + 1, mid + 1, r);
pushup(rt);
}
void pushdown(int rt)
{
if (tree[rt].lazy)
{
tree[rt * 2].lazy += tree[rt].lazy;
tree[rt * 2 + 1].lazy += tree[rt].lazy;
double x, y, cs, si;
int change;
change = tree[rt ].lazy;
cs = cos(change*pi / 180.0), si = sin(change*pi / 180.0);
x = tree[rt * 2].x, y = tree[rt * 2].y;
tree[rt * 2].x = x * cs - y * si;
tree[rt * 2].y = y * cs + x * si;
x = tree[rt * 2 + 1].x, y = tree[rt * 2 + 1].y;
tree[rt * 2 + 1].x = x * cs - y * si;
tree[rt * 2 + 1].y = y * cs + x * si;
tree[rt].lazy = 0;
}
}
void update(int rt, int l, int r, int L, int R, int change)//
{
if (L <= l && r <= R)
{
double x = tree[rt].x, y = tree[rt].y;
double cs = cos(change*pi / 180.0), si = sin(change*pi / 180.0);
tree[rt].x = x * cs - y * si;
tree[rt].y = y * cs + x * si;
tree[rt].lazy += change;
return;
}
pushdown(rt);
int mid = (l + r) / 2;
if (R <= mid)
{
update(rt * 2, l, mid, L, R, change);
}
else if (L >= mid + 1)
{
update(rt * 2 + 1, mid + 1, r, L, R, change);
}
else
{
update(rt * 2, l, mid, L, R, change);
update(rt * 2 + 1, mid + 1, r, L, R, change);
}
pushup(rt);
}
int main()
{
int n, m;
while (~scanf("%d%d", &n, &m))
{
build(1, 1, n);
for (int i = 1; i <= n + 1; i++)
{
deg[i] = 180;
}
while (m--)
{
int s, goal;
scanf("%d%d", &s, &goal);
update(1, 1, n, s + 1, n, goal -deg[s]);
deg[s] = goal;
printf("%.2f %.2f\n", tree[1].x, tree[1].y);
}
}
}