P6327 區間加區間sin和(題解)
阿新 • • 發佈:2021-10-11
思路:根據\(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; }