P6327 区间加区间sin和(题解)
思路:根据\(sin\) ,\(cos\)的运算来做。我们有:
\[sin(a+b) = sin(a) * cos(b) + sin(b)*cos(a)
\]
\[cos(a+b) = cos(a) * cos(b) - sin(a) * sin(b)
\]
所以线段树维护每个节点的\(sin\),\(cos\) 就能得到答案,需要注意的是懒标记应开\(longlong\)
\(Code:\)
#include <algorithm>
#include <bitset>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <deque>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <unordered_map>
#include <vector>
#define ch() getchar()
#define pc(x) putchar(x)
#define rep(i, a, b) for (auto i = a; i <= b; ++i)
#define bep(i, a, b) for (auto i = a; i >= b; --i)
#define lowbit(x) x &(-x)
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define PI acos(-1)
using namespace std;
template <typename T>
void read(T &x) {
static char c;
static int f;
for (c = ch(), f = 1; c < '0' || c > '9'; c = ch())
if (c == '-') f = -f;
for (x = 0; c >= '0' && c <= '9'; c = ch()) x = x * 10 + (c & 15);
x *= f;
}
template <typename T>
void write(T x) {
static char q[65];
int cnt = 0;
if (x < 0) pc('-'), x = -x;
q[++cnt] = x % 10, x /= 10;
while (x) q[++cnt] = x % 10, x /= 10;
while (cnt) pc(q[cnt--] + '0');
}
const int N = 2e5 + 10;
int n;
int a[N];
struct segmentTree {
struct node {
int l, r, L, R;
ll add;
double sina, cosa;
} tr[N << 3];
inline void update(int u, double sinx, double cosx) {
double sins = tr[u].sina, coss = tr[u].cosa;
tr[u].sina = sins * cosx + coss * sinx;
tr[u].cosa = coss * cosx - sins * sinx;
}
inline void pushup(int p) {
tr[p].sina =
tr[tr[p].l].sina +
tr[tr[p].r].sina; // +
// tr[tr[p].r].sina * tr[tr[p].l].cosa);
tr[p].cosa = tr[tr[p].l].cosa + tr[tr[p].r].cosa;
}
inline void pushdown(int p) {
if (tr[p].add != 0) {
ll d = tr[p].add;
tr[p].add = 0;
double rs = tr[tr[p].r].sina, ls = tr[tr[p].l].sina;
(tr[tr[p].r].sina =
sin(d) * tr[tr[p].r].cosa + tr[tr[p].r].sina * cos(d));
(tr[tr[p].r].cosa = cos(d) * tr[tr[p].r].cosa - rs * sin(d));
(tr[tr[p].l].sina =
sin(d) * tr[tr[p].l].cosa + tr[tr[p].l].sina * cos(d));
(tr[tr[p].l].cosa = cos(d) * tr[tr[p].l].cosa - ls * sin(d));
(tr[tr[p].l].add += d);
(tr[tr[p].r].add += d);
}
}
inline void build(int l, int r, int p) {
tr[p].l = p << 1;
tr[p].r = p << 1 | 1;
tr[p].L = l, tr[p].R = r;
tr[p].add = 0;
if (l == r) {
tr[p].sina = sin(a[l]), tr[p].add = 0;
tr[p].cosa = cos(a[l]);
// printf("%d %d %.3lf\n", tr[p].L, tr[p].R, tr[p].sina);
return;
}
int mid = l + r >> 1;
build(l, mid, tr[p].l), build(mid + 1, r, tr[p].r);
pushup(p);
// printf("%d %d %.1lf\n",tr[p].L,tr[p].R,tr[p].sina);
}
inline void add(int l, int r, int p, int k) {
if (tr[p].L >= l && tr[p].R <= r) {
double ps = tr[p].sina;
tr[p].sina = tr[p].sina * cos(k) + tr[p].cosa * sin(k);
tr[p].cosa = tr[p].cosa * cos(k) - ps * sin(k);
tr[p].add += k;
return;
}
pushdown(p);
if (tr[tr[p].l].R >= l) add(l, r, tr[p].l, k);
if (tr[tr[p].r].L <= r) add(l, r, tr[p].r, k);
pushup(p);
}
inline double ask(int l, int r, int p) {
double ret = 0.0;
pushdown(p);
if (tr[p].L >= l && tr[p].R <= r) {
// printf("~~%.1lf %.1lf\n", tr[p].sina, tr[p].cosa);
return tr[p].sina;
}
if (tr[tr[p].l].R >= l) {
(ret = ask(l, r, tr[p].l));
// printf("~##!!!%d %d %.1lf\n", tr[p].L, tr[p].R, ret.first);
}
if (tr[tr[p].r].L <= r) {
ret += ask(l,r,tr[p].r);
// printf("~#!!!%d %d %.1lf\n", tr[p].L, tr[p].R, ret.first);
}
// printf("~!!!%d %d %.1lf\n", tr[p].L, tr[p].R, ret.first);
return ret;
}
} T;
int q;
void solve() {
read(n);
rep(i, 1, n) read(a[i]);
T.build(1, n, 1);
// printf("%.1lf\n", T.ask(3, 3, 1).first);
read(q);
while (q--) {
int v, op, l, r;
read(op);
read(l);
read(r);
if (op == 1) {
read(v);
T.add(l, r, 1, v);
} else {
printf("%.1lf\n", T.ask(l, r, 1));
}
}
}
signed main(int argc, char const *argv[]) {
solve();
return 0;
}