P6327 区间加区间sin和

P6327 区间加区间sin和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

考虑

\[\sin (\alpha + \beta) = \sin\alpha\cos\beta + \cos\alpha\sin\beta\\ \cos(\alpha + \beta) = \cos\alpha\cos\beta - \sin\alpha\sin\beta \]

所以

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

\(s\) 表示 \(\sin\) 和,\(c\) 表示 \(\cos\) 和,那么对于每一次更新有:

\(s \gets s\cos v + c\sin v\)\(c \gets c \cos v - s \sin v\)

然后就可以直接线段树维护了。

有个坑:懒标记需要开 long long。

/*
 * @Author: crab-in-the-northeast 
 * @Date: 2023-01-03 11:17:34 
 * @Last Modified by: crab-in-the-northeast
 * @Last Modified time: 2023-01-03 11:56:55
 */
#include <bits/stdc++.h>
#define int long long
inline int read() {
    int x = 0;
    bool f = true;
    char ch = getchar();
    for (; !isdigit(ch); ch = getchar())
        if (ch == '-')
            f = false;
    for (; isdigit(ch); ch = getchar())
        x = (x << 1) + (x << 3) + ch - '0';
    return f ? x : (~(x - 1));
}
inline int ls(int p) {
    return p << 1;
}
inline int rs(int p) {
    return p << 1 | 1;
}
const int maxn = (int)2e5 + 5;

double si[maxn << 2], co[maxn << 2];
int der[maxn << 2];

inline void up(int p) {
    si[p] = si[ls(p)] + si[rs(p)];
    co[p] = co[ls(p)] + co[rs(p)];
}

inline void build(int p, int l, int r) {
    if (l == r) {
        int x = read();
        si[p] = sin(x);
        co[p] = cos(x);
        return ;
    }
    
    int mid = (l + r) >> 1;
    build(ls(p), l, mid);
    build(rs(p), mid + 1, r);
    up(p);
}

inline void update(int p, int v) {
    double s = si[p], c = co[p];
    si[p] = s * cos(v) + c * sin(v);
    co[p] = c * cos(v) - s * sin(v);
}

inline void down(int p) {
    if (!der[p])
        return ;
    update(ls(p), der[p]);
    update(rs(p), der[p]);
    der[ls(p)] += der[p];
    der[rs(p)] += der[p];
    der[p] = 0;
}

double query(int p, int l, int r, int L, int R) {
    if (L <= l && r <= R)
        return si[p];
    down(p);
    int mid = (l + r) >> 1;
    double ans = 0;
    if (L <= mid)
        ans = query(ls(p), l, mid, L, R);
    if (R > mid)
        ans += query(rs(p), mid + 1, r, L, R);
    return ans;
}

void add(int p, int l, int r, int L, int R, int v) {
    if (L <= l && r <= R) {
        update(p, v);
        der[p] += v;
        return ;
    }
    down(p);
    int mid = (l + r) >> 1;
    if (L <= mid)
        add(ls(p), l, mid, L, R, v);
    if (R > mid)
        add(rs(p), mid + 1, r, L, R, v);
    up(p);
}

signed main() {
    int n = read();
    build(1, 1, n);
    int m = read();
    while (m--) {
        int op = read(), l = read(), r = read();
        if (op == 1) {
            int v = read();
            add(1, 1, n, l, r, v);
        } else {
            printf("%.1f\n", query(1, 1, n, l, r));
        }
    }
    return 0;
}
posted @ 2023-01-03 12:16  dbxxx  阅读(33)  评论(0编辑  收藏  举报