余弦

Description

给定长度为 𝑁 的实数序列 𝐴𝑖(1 ≤ 𝑖 ≤ 𝑁), 你需要在数列上进行两类操作:

1. 把 𝑙 ≤ 𝑖 ≤ 𝑟 中的每个 𝐴𝑖 加上实数 𝑣。

2. 求 𝑙 ≤ 𝑖 ≤ 𝑟 中 cos(𝐴𝑖) 的和。 

Input

输入包含多组数据,最开头的正整数 T (T≤ 5) 指明了数据组数。

对于每组数据:第一行 2 个整数 N、M,表示数列长度与操作个数。

第二行 N 个实数 𝐴𝑖(|𝐴𝑖| ≤ 100),小数点后最多有 3 位小数。

接下来 M 行每行形如“1 𝑙 𝑟 𝑣” 或 “2 𝑙 𝑟”。

前者表示一个第 1 类操作,后者表示一个第 2 类操作。

其中 𝑙, 𝑟(1 ≤ 𝑙 ≤ 𝑟 ≤ 𝑁) 是整数,而𝑣(|𝑣| ≤ 100)是实数,小数点后最多有 3位小数。 

Output

对于每组数据,先输出一行 "Case #k:",其中 k 是该组数据的编号,从 1 开始。

对于每组数据中的每个第 2 类操作,输出一个实数表示答案,保留 3 位小数。

Sample Input 1

3
3 3
0 -2 -6
1 1 2 -7
2 1 2
2 2 3
5 4
4 2 4 -0 -4
1 1 4 2
2 4 5
1 3 5 5
2 2 3
7 3
0.123 -19.002 -57.507 34.434 -80.886 -17.115 69.843
2 2 7
1 2 7 16.341
2 1 3

Sample Output 1

Case #1:
-0.157
0.049
Case #2:
-1.070
-0.649
Case #3:
1.854
-0.842

Hint

对于 20%的数据,1 ≤ N, M ≤ 1000。

对于另外 20%的数据,没有 1 类操作。

对于另外 20%的数据,1 类操作均在 2 类操作之前。

对于 100%的数据,1 ≤ N, M ≤ 200000。

 

(我不会说我因为传参写错了而调了一晚上的);

其实是水题;

你在每个节点维护sin值的和还有cos值的和;

你加一个数, 根据高一的知识,∑cos(ai+c)=∑(cosai*cosc-sinai*sinc);

而上面的式子可以化简为∑cos(ai+c)= cosc∑cosai - sincΣsinai , 显然可以快速合并;

合并sin值同理;

代码奉上:

//By zZhBr
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;

inline int read()
{
    int res=0;bool flag=0;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')flag=1;ch=getchar();
    }while(isdigit(ch)){res=(res<<3)+(res<<1)+(ch-'0');ch=getchar();
    }return flag?-res:res;
}
const int N = 200010;
const double eps = 1e-9;

int n, m, T;
double a[N];
int cnt = 1;

struct SegmentTree
{
    int l, r;
    double sinn, coss;
    double flag;
    void clean()
    {
        l = r = 0;
        sinn = coss = 0;
        flag = 0;
    }
}t[N<<2];
#define ls(x) x << 1
#define rs(x) x << 1 | 1

inline void pushup(int o)
{
    t[o].sinn = t[ls(o)].sinn + t[rs(o)].sinn;
    t[o].coss = t[ls(o)].coss + t[rs(o)].coss;
    t[o].l = t[ls(o)].l, t[o].r = t[rs(o)].r;
}

inline void build(int l, int r, int o)
{
    if (l == r)
    {
        t[o].l = t[o].r = l;
        t[o].sinn = sin(a[l]);
        t[o].coss = cos(a[l]);
        t[o].flag = 0.0;
        return;
    }
    int mid = l + r >> 1;
    build(l, mid, o<<1);
    build(mid + 1, r, o<<1|1);
    pushup(o);
}

inline void spread(int o)
{
    if (t[o].flag == 0) return;
    double c = t[o].flag;
    
    double X = t[ls(o)].coss, Y = t[ls(o)].sinn;
    t[ls(o)].coss = cos(c) * X - sin(c) * Y;
    t[ls(o)].sinn = sin(c) * X + cos(c) * Y;
    
    X = t[rs(o)].coss, Y = t[rs(o)].sinn;
    t[rs(o)].coss = cos(c) * X - sin(c) * Y;
    t[rs(o)].sinn = sin(c) * X + cos(c) * Y;
    
    t[ls(o)].flag += c;
    t[rs(o)].flag += c;
    t[o].flag = 0;
    
}

inline void change(int li, int ri, int o, double v)
{
    if (li <= t[o].l and ri >= t[o].r)
    {
        double la=t[o].coss;
        t[o].coss = cos(v) * t[o].coss - sin(v) * t[o].sinn;
        t[o].sinn = sin(v) * la + cos(v) * t[o].sinn;
        t[o].flag += v;
        return;
    }
    spread(o);
    int mid = t[o].l + t[o].r >> 1;
    if (li <= mid) change(li, ri,ls(o), v);
    if (ri > mid) change(li, ri, rs(o), v);
    pushup(o);
}

inline double query(int o, int li, int ri)
{
    if (li <= t[o].l and ri >= t[o].r)
    {
        return t[o].coss;
    }
    spread(o);
    double res = 0;
    int mid = t[o].l + t[o].r >> 1;
    if (li <= mid) res += query(ls(o), li, ri);
    if (ri > mid) res += query(rs(o), li, ri);
    return res;
}

inline void init(int x)
{
    cnt = 1;
    for (register int i = 1 ; i <= x ; i ++)
    {
        t[i].clean();
    }
}

int main()
{
    T = read();
    for (register int tiime = 1 ; tiime <= T ;  tiime++)
    {
        printf("Case #%d:\n", tiime);        
        n = read(), m = read();        
        init(n<<2);
        for (register int i = 1 ; i <= n ; i ++) cin >> a[i];
        build(1, n, 1);
        
        while (m--)
        {
            int opt = read();
            if (opt == 1)
            {
                int x = read(), y = read();
                double v;
                cin >> v;
                change(x, y, 1, v);
            }
            if (opt == 2)
            {
                int x = read(), y = read();
                printf("%.3lf\n", query(1, x, y));
            }
        }
        init(n<<1);
    }
}

 

 

 

posted @ 2018-05-30 21:47  zZhBr  阅读(289)  评论(0编辑  收藏  举报