洛谷P6327 区间加区间sin和 题解

本文详细解析了洛谷P6327题目的解题思路,主要涉及区间加操作和求区间sin和的问题。通过利用三角恒等式,维护sin和cos的两个量,实现了区间更新和查询的高效算法。在实现过程中需要注意数值精度问题和更新传播,以避免计算错误。提供的C++代码展示了如何构建并维护这个数据结构,以处理区间操作和查询请求。
摘要由CSDN通过智能技术生成

洛谷P6327 区间加区间sin和 题解

题目链接:洛谷P6327 区间加区间sin和 题解

题意:维护一个数据结构,支持

  1. 区间加 v v v
  2. 询问区间 ∑ i = 1 r sin ⁡ a i \sum\limits_{i=1}^{r}\sin a_i i=1rsinai

注意到
sin ⁡ ( a + x ) = sin ⁡ a cos ⁡ x + cos ⁡ a sin ⁡ x cos ⁡ ( a + x ) = cos ⁡ a cos ⁡ x − sin ⁡ a sin ⁡ x \begin{aligned} \sin(a+x)&=\sin a\cos x+\cos a \sin x\\ \cos(a+x)&=\cos a\cos x-\sin a \sin x \end{aligned} sin(a+x)cos(a+x)=sinacosx+cosasinx=cosacosxsinasinx
直接维护即可两个量即可

注意点

  1. 更新的时候拿之前更新过的sin去更新cos,爆零。
  2. 不开long long,爆零。
  3. 不下传标记,爆零。
  4. 可以适当卡卡常(逃

代码如下

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(2e5+15)
#define ls(at) (at<<1)
#define rs(at) (at<<1|1)
namespace FastIO
{
    #define gc() readchar()
    #define pc(a) putchar(a)
    #define SIZ (int)(1e6+15)
    char buf1[SIZ],*p1,*p2;
    char readchar()
    {
        if(p1==p2)p1=buf1,p2=buf1+fread(buf1,1,SIZ,stdin);
        return p1==p2?EOF:*p1++;
    }
    template<typename T>void read(T &k)
    {
        char ch=gc();T x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=gc();}
        while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=gc();}
        k=x*f;
    }
    template<typename T>void write(T k)
    {
        if(k<0){k=-k;pc('-');}
        static T stk[66];T top=0;
        do{stk[top++]=k%10,k/=10;}while(k);
        while(top){pc(stk[--top]+'0');}
    }
}using namespace FastIO;
// #define double long double
// const double eps=1e-15;
double sinx[N<<2],cosx[N<<2];
int tag[N<<2];
int n,m,a[N];
void push_up(int at)
{
    sinx[at]=sinx[ls(at)]+sinx[rs(at)];
    cosx[at]=cosx[ls(at)]+cosx[rs(at)];
}
void build(int l,int r,int at)
{
    if(l==r)
    {
        sinx[at]=sin(a[l]);
        cosx[at]=cos(a[l]);
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,ls(at));
    build(mid+1,r,rs(at));
    push_up(at);
}
void proc(int at,int k)
{
    double sink=sin(k),cosk=cos(k);
    double sina=sinx[at],cosa=cosx[at];
    sinx[at]=sina*cosk+cosa*sink;
    cosx[at]=cosa*cosk-sina*sink;
    tag[at]+=k;
}
void push_down(int at)
{
    int k=tag[at];
    if(k)
    {
        proc(ls(at),k);
        proc(rs(at),k);
        tag[at]=0;
    }
}
void update(int nl,int nr,int l,int r,int k,int at)
{
    if(nl<=l&&r<=nr)
    {
        proc(at,k);
        return;
    }
    int mid=(l+r)>>1;
    push_down(at);
    if(nl<=mid)update(nl,nr,l,mid,k,ls(at));
    if(nr>mid)update(nl,nr,mid+1,r,k,rs(at));
    push_up(at);
}
double query(int nl,int nr,int l,int r,int at)
{
    if(nl<=l&&r<=nr)return sinx[at];
    if(nl>r||nr<l)return 0;
    push_down(at);
    int mid=(l+r)>>1;
    return query(nl,nr,l,mid,ls(at))+query(nl,nr,mid+1,r,rs(at));
}
signed main()
{
    // ios::sync_with_stdio(0);
    // cin.tie(0);cout.tie(0);
    // cout << fixed << setprecision(1);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    read(n);
    for(int i=1; i<=n; i++)
        read(a[i]);
    build(1,n,1);
    int Q;read(Q);
    int op,l,r,v;
    while(Q--)
    {
        read(op);read(l);read(r);
        if(op==1){read(v);update(l,r,1,n,v,1);}
        else printf("%.1lf\n",query(l,r,1,n,1));
    }
    return 0;
}

转载请说明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值