P6327 区间加区间sin和

该文介绍了一种使用线段树数据结构来高效维护区间内正弦和余弦值的方法。在更新角度时,通过三角函数的性质进行区间更新,并通过pushdown操作传播到子节点。此方法适用于处理与三角函数相关的区间查询问题,避免了每次查询时计算三角函数的开销。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

知识点:线段树,数学

这么简单的题竟然过了小半天我再一次看的时候才写出来,就是推一下三角函数的式子就发现了,需要维护区间的正弦余弦和,这样,加上一个角度值的时候就可以方便的更新了,然后向下传递的时候这个角度也是直接累加的,总之还是很简单的一道题,适合刚入门线段树的新手

没有卡常,就是他们说的可以先预处理需要求三角函数的值,用的时候直接查询,三角函数的调用好像还费点时间,最后也没有四舍五入啥的,就直接过了

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 5;

struct tree {
	int l, r;
	double sin, cos, add;
};

int a[N];
tree t[N * 4];

void build(int p, int l, int r) {
	t[p].l = l; t[p].r = r;
	if (l == r) {
		t[p].sin = sin(a[l]);
		t[p].cos = cos(a[l]);
		return;
	}
	int mid = (l + r) / 2;
	build(p * 2, l, mid);
	build(p * 2 + 1, mid + 1, r);
	t[p].sin = t[p * 2].sin + t[p * 2 + 1].sin;
	t[p].cos = t[p * 2].cos + t[p * 2 + 1].cos;
}

void pushdown(int p) {
	double t1, t2;
	t1 = t[p * 2].sin * cos(t[p].add) + t[p * 2].cos * sin(t[p].add);
	t2 = t[p * 2].cos * cos(t[p].add) - t[p * 2].sin * sin(t[p].add);
	t[p * 2].sin = t1; t[p * 2].cos = t2;
	t1 = t[p * 2 + 1].sin * cos(t[p].add) + t[p * 2 + 1].cos * sin(t[p].add);
	t2 = t[p * 2 + 1].cos * cos(t[p].add) - t[p * 2 + 1].sin * sin(t[p].add);
	t[p * 2 + 1].sin = t1; t[p * 2 + 1].cos = t2;
	t[p * 2].add += t[p].add; t[p * 2 + 1].add += t[p].add;
	t[p].add = 0;
}

void update(int p, int l, int r, int x) {
	if (l <= t[p].l && r >= t[p].r) {
		double t1 = t[p].sin * cos(x) + t[p].cos * sin(x);
		double t2 = t[p].cos * cos(x) - t[p].sin * sin(x);
		t[p].sin = t1; t[p].cos = t2;
		t[p].add += x;
		return;
	}
	pushdown(p);
	int mid = (t[p].l + t[p].r) / 2;
	if (l <= mid) update(p * 2, l, r, x);
	if (r > mid) update(p * 2 + 1, l, r, x);
	t[p].sin = t[p * 2].sin + t[p * 2 + 1].sin;
	t[p].cos = t[p * 2].cos + t[p * 2 + 1].cos;
}

double query(int p, int l, int r) {
	if (l <= t[p].l && r >= t[p].r) return t[p].sin;
	pushdown(p);
	int mid = (t[p].l + t[p].r) / 2;
	double val = 0;
	if (l <= mid) val += query(p * 2, l, r);
	if (r > mid) val += query(p * 2 + 1, l, r);
	return val;
}

int main() {
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) {
		scanf("%d", &a[i]);
	}
	build(1, 1, n);
	int m;
	cin >> m;
	while (m--) {
		int op, x, y, z;
		scanf("%d%d%d", &op, &x, &y);
		if (op == 1) {
			scanf("%d", &z);
			update(1, x, y, z);
		} else {
			printf("%.1f\n", query(1, x, y));
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值