目录
- 题目内容
- 思路
- 代码
题目内容
题目链接
给出一个长为 \(n\) 的整数序列 \(a\),支持两种操作:
-
给定 \(l,r,v\),将 \(a\) 中下标 \(\in[l,r]\) 的数全部加上 \(v\)。
-
给定 \(l,r\),查询 \(\sum\limits_{i=l}^{r}sin(a_i)\)。
\(1\le n,m,a_i,v\le 2\times10^5,1\le l\le r\le n\)。
思路
只能说身为 lxl 的题有单 \(\log\) 做法数据范围才到 \(2e5\) 还是太收敛了。
前置知识:
弧度制
三角恒等式
于是在线段树上维护 \(\sum\limits_{i=L}^{R}sin(a_i)\) 和 \(\sum\limits_{i=L}^{R}cos(a_i)\)(注意区分线段树上的 \(L\) 和询问的 \(l\))。这样的话查询是显然的。修改时套用上面的公式:
\[\begin{aligned}\sum\limits_{i=L}^{R}sin(a_i+x)&=\sum\limits_{i=L}^{R}[sin(a_i)\times cos(x)+cos(a_i)\times sin(x)]\\&=\sum\limits_{i=L}^{R}[sin(a_i)\times cos(x)]+\sum\limits_{i=L}^{R}[cos(a_i)\times sin(x)]\\&=cos(x)\times\sum\limits_{i=L}^{R}sin(a_i)+sin(x)\times\sum\limits_{i=L}^{R}cos(a_i)\end{aligned}
\]
然后就做完了。维护 cos 值使用另一个公式:
\[\begin{aligned}\sum\limits_{i=L}^{R}cos(a_i+x)&=\sum\limits_{i=L}^{R}[cos(a_i)\times cos(x)-sin(a_i)\times sin(x)]\\&=\sum\limits_{i=L}^{R}[cos(a_i)\times cos(x)]-\sum\limits_{i=L}^{R}[sin(a_i)\times sin(x)]\\&=cos(x)\times\sum\limits_{i=L}^{R}cos(a_i)-sin(x)\times\sum\limits_{i=L}^{R}sin(a_i)\end{aligned}
\]
注意 lazy 标记累加有可能爆 int。注意修改时要开中间变量,且要开成 double。
代码
#include<bits/stdc++.h>
using namespace std;
#define il inline
#define ri register int
#define inf 0x3f3f3f3f
int a,b[200002],c,in,u,v,w;
struct Segment_Tree
{#define N 800008int left[N],right[N];long long lazy[N];double sn[N],cs[N];il int ls(int x){return x<<1;}il int rs(int x){return x<<1|1;}il void pushup(int x){sn[x]=sn[ls(x)]+sn[rs(x)];cs[x]=cs[ls(x)]+cs[rs(x)];}il void pushdown(int x){if(lazy[x]){lazy[ls(x)]+=lazy[x];lazy[rs(x)]+=lazy[x];register double sin0=sn[ls(x)],cos0=cs[ls(x)];sn[ls(x)]=cos(lazy[x])*sin0+sin(lazy[x])*cos0;cs[ls(x)]=cos(lazy[x])*cos0-sin(lazy[x])*sin0;sin0=sn[rs(x)],cos0=cs[rs(x)];sn[rs(x)]=cos(lazy[x])*sin0+sin(lazy[x])*cos0;cs[rs(x)]=cos(lazy[x])*cos0-sin(lazy[x])*sin0;lazy[x]=0;}}void build(int x,int lt,int rt){left[x]=lt;right[x]=rt;if(lt==rt){sn[x]=sin(b[lt]);cs[x]=cos(b[lt]);return;}ri me=(lt+rt)>>1;build(ls(x),lt,me);build(rs(x),me+1,rt);pushup(x);}void add(int x,int lt,int rt,int y){if(lt<=left[x]&&right[x]<=rt){lazy[x]+=y;register double sin0=sn[x],cos0=cs[x];sn[x]=cos(y)*sin0+sin(y)*cos0;cs[x]=cos(y)*cos0-sin(y)*sin0;return;}pushdown(x);ri me=(left[x]+right[x])>>1;if(lt<=me){add(ls(x),lt,rt,y);}if(rt>me){add(rs(x),lt,rt,y);}pushup(x);}double find(int x,int lt,int rt){if(lt<=left[x]&&right[x]<=rt){return sn[x];}pushdown(x);ri me=(left[x]+right[x])>>1;register double rn=0;if(lt<=me){rn+=find(ls(x),lt,rt);}if(rt>me){rn+=find(rs(x),lt,rt);}return rn;}#undef N
}st;
int main()
{scanf("%d",&a);for(ri i=1;i<=a;i++){scanf("%d",&b[i]);}st.build(1,1,a);scanf("%d",&c);while(c--){scanf("%d",&in);if(in==1){scanf("%d%d%d",&u,&v,&w);st.add(1,u,v,w);}else{scanf("%d%d",&u,&v);printf("%.1lf\n",st.find(1,u,v));}}return 0;
}