luoguP6327 区间加区间sin和(线段树 sin公式)

简介: luoguP6327 区间加区间sin和(线段树 sin公式)

原题链接

20200401134307494.png

思路:

区间修改首先想到的就是线段树,考虑怎么样维护一个懒标。

标记跟标记,值跟值的合并都可以直接合并,如何处理标记跟值的合并。

∑ s i n ( a i ) − > ∑ s i n ( a i + v ) \sum sin(a_i)->\sum sin(a_i+v)∑sin(ai)−>∑sin(ai+v)

可以按照以下公式拆开:

20200401134307494.png

∑sin(a+v)=∑(sina)∗cosv+∑(cosa)∗sinv

对于每个节点维护s i n a i和c o s a i的和就可以了。


代码:

const int maxn=2e5+7,inf=0x3f3f3f3f;
const double eps=1e-5;
struct node{
  int l,r;
  ll laz;
  double sum_sin,sum_cos; 
}tr[maxn*4];
int n,m,a[maxn];
double sinv,cosv;
void pushup(int u){
  tr[u].sum_sin=tr[u<<1].sum_sin+tr[u<<1|1].sum_sin;
  tr[u].sum_cos=tr[u<<1].sum_cos+tr[u<<1|1].sum_cos;
}
void add(int u,double sinx,double cosx){
  double siny=tr[u].sum_sin,cosy=tr[u].sum_cos;
  tr[u].sum_sin=siny*cosx+cosy*sinx;
  tr[u].sum_cos=cosx*cosy-sinx*siny;
}
void pushdown(int u){
  if(tr[u].laz){
    double sinx=sin(tr[u].laz),cosx=cos(tr[u].laz);
    add(u<<1,sinx,cosx);
    add(u<<1|1,sinx,cosx);
    tr[u<<1].laz+=tr[u].laz;
    tr[u<<1|1].laz+=tr[u].laz;
    tr[u].laz=0;
  }
}
void build(int u,int l,int r){
  tr[u].l=l,tr[u].r=r;
  if(l==r){
    tr[u].laz=0;
    tr[u].sum_sin=sin(a[l]);
    tr[u].sum_cos=cos(a[l]);
    return ;
  }
  int mid=(l+r)/2;
  build(u<<1,l,mid);build(u<<1|1,mid+1,r);
  pushup(u);
}
void update(int u,int l,int r,int ql,int qr,int v){
  if(l>=ql&&r<=qr){
    add(u,sinv,cosv);
    tr[u].laz+=v;
    return ;
  }
  int mid=(l+r)/2;
  pushdown(u);
  if(ql<=mid) update(u<<1,l,mid,ql,qr,v);
  if(qr>mid) update(u<<1|1,mid+1,r,ql,qr,v);
  pushup(u);
}
double query(int u,int l,int r,int ql,int qr){
  if(l>=ql&&r<=qr){
    return tr[u].sum_sin;
  }
  pushdown(u);
  double res=0;
  int mid=(l+r)/2;
  if(ql<=mid) res+=query(u<<1,l,mid,ql,qr);
  if(qr>mid) res+=query(u<<1|1,mid+1,r,ql,qr);
  return res;
}
int main(){
  n=read;
  rep(i,1,n) a[i]=read;
  build(1,1,n);
  m=read;
  while(m--){
    int op=read,l=read,r=read;
    if(op==1){
      int v=read;
      sinv=sin(v),cosv=cos(v);
      update(1,1,n,l,r,v);
    }
    else printf("%.1f\n",query(1,1,n,l,r));
  }
    return 0;
}
目录
相关文章
|
1月前
|
人工智能
PTA-一维数组最大值和最小值交换
一维数组最大值和最小值交换
54 0
|
12天前
【P1035】级数求和
【P1035】级数求和
|
1月前
DAY-4 | 力扣 - 求自身以外数组的乘积:区间划分,左右累乘,巧求乘积
该文档是关于LeetCode上的一道题目“Product of Array Except Self”的题解。提供了两种解题方法,一是暴力破解,即计算所有数的乘积后再逐个除以当前元素;二是左右累乘法,通过两次遍历数组分别计算左侧和右侧元素的乘积,避免了除法操作。其中,左右累乘法更优,代码实现中展示了这种方法。
24 1
|
1月前
|
人工智能 BI
区间问题之区间选点
区间问题之区间选点
|
1月前
|
C++
汇总区间(C++)
汇总区间(C++)
29 0
|
10月前
|
人工智能 算法
动态规划之区间一维
噩梦中的仙境:动态规划之区间一维
41 0
动态规划之区间一维
|
11月前
|
人工智能 算法 BI
贪心算法——区间选点与最大不相交区间数
贪心算法——区间选点与最大不相交区间数
50 0
|
自然语言处理 算法 Python
利用函数求出一个数组最大三个数的乘积
利用函数求出一个数组最大三个数的乘积
96 0