洛谷 P6327 区间加区间sin和

Description

洛谷传送门

似乎是一道前 \(Ynoi\),不过反正现在不是了。

Solution

题目名字已经暗示我们要使用线段树之类的数据结构了。

看一眼题面,好吧,就是线段树维护。

本题需要一点数学基础。

\[sin(a + b) = sin(a) * cos(b) + cos(a) * sin(b) \]

\[cos(a + b) = cos(a) * cos(b) - sin(a) * sin(b) \]

所以,我们需要维护一下区间 \(sin\) 和,同时也要维护一下区间 \(cos\) 和。

然后就没什么了,注意这道题还卡精度。

在区间加 \(k\) 时,要把 \(sin(k)\)\(cos(k)\) 提前存下来,不能每次都计算一遍,不然会被卡。

我是不会告诉你,我因为不知道怎么计算 sin 看了一个晚上,后来一看题解发现有函数……

Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define ls rt << 1
#define rs rt << 1 | 1
#define ll long long

using namespace std;

template <typename T> inline void read(T &x){
	x = 0; char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
}

const int N = 2e5 + 10;
int n, m;
int a[N];
double ssin[N << 2], scos[N << 2];
ll lazy[N << 2];
double sink, cosk;

inline void pushup(int rt){
	ssin[rt] = ssin[ls] + ssin[rs];
	scos[rt] = scos[ls] + scos[rs];
}

inline void add(int a, double sinb, double cosb){
	double sina = ssin[a], cosa = scos[a];
	ssin[a] = sina * cosb + cosa * sinb;
	scos[a] = cosa * cosb - sina * sinb;
}

inline void pushdown(int rt){
	if(lazy[rt]){
		double sinb = sin(lazy[rt]), cosb = cos(lazy[rt]);
		add(ls, sinb, cosb);
		add(rs, sinb, cosb);
		lazy[ls] += lazy[rt], lazy[rs] += lazy[rt];
		lazy[rt] = 0;
	}
}

inline void build(int l, int r, int rt){
	if(l == r){
		ssin[rt] = sin(a[l]);
		scos[rt] = cos(a[l]);
		return;
	}
	int mid = (l + r) >> 1;
	build(l, mid, ls);
	build(mid + 1, r, rs);
	pushup(rt);
}

inline void update(int L, int R, int k, int l, int r, int rt){
	if(L <= l && r <= R){
		add(rt, sink, cosk);
		lazy[rt] += k;
		return;
	}
	pushdown(rt);
	int mid = (l + r) >> 1;
	if(L <= mid) update(L, R, k, l, mid, ls);
	if(R > mid) update(L, R, k, mid + 1, r, rs);
	pushup(rt);
}

inline double query(int L, int R, int l, int r, int rt){
	if(L <= l && r <= R)
		return ssin[rt];
	pushdown(rt);
	int mid = (l + r) >> 1;
	double res = 0;
	if(L <= mid) res += query(L, R, l, mid, ls);
	if(R > mid) res += query(L, R, mid + 1, r, rs);
	return res;
}

int main(){
	read(n);
	for(int i = 1; i <= n; i++)
		read(a[i]);
	build(1, n, 1);
	read(m);
	for(int i = 1; i <= m; i++){
		int op, l, r, k;
		read(op), read(l), read(r);
		if(op == 1){
			read(k);
			sink = sin(k), cosk = cos(k);
			update(l, r, k, 1, n, 1);
		}else printf("%.1lf\n", query(l, r, 1, n, 1));
	}
	return 0;
}

End

posted @ 2021-10-15 16:53  xixike  阅读(94)  评论(0编辑  收藏  举报