Crane POJ - 2991

这篇博客介绍了如何利用向量旋转的数学公式和树状数组(也称作线段树)解决动态区间旋转的问题。作者在解决过程中遇到了时间复杂度过高的问题,通过引入懒惰标记(lazy tag)优化了更新过程,最终实现了高效的解决方案。博客内容涵盖了向量旋转的公式的推导、树状数组的构建、更新和查询操作,以及在解决实际问题中的应用。
摘要由CSDN通过智能技术生成

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)=cosAcosBsinAsinB
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=Rx0cosBRy0sinB
x 1 = x 0 ∗ c o s B − y 0 ∗ s i n B x_1=x_0*cosB-y_0*sinB x1=x0cosBy0sinB
同理
y 1 = y 0 ∗ c o s B + x 0 ∗ s i n B y_1=y_0*cosB+x_0*sinB y1=y0cosB+x0sinB

卡我一晚上的点:
pushdown的时候,用的是 l a z y r t lazy_{rt} lazyrt来更新两个子节点,而不是更新完后的 l a z y r t ∗ 2 lazy_{rt*2} lazyrt2 l a z y r t ∗ 2 + 1 lazy_{rt*2+1} lazyrt2+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);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值