洛谷 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;
}