【题解】P6327 区间加区间 sin 和
题目内容
给出一个长为 \(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 800008
int 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;
}
浙公网安备 33010602011771号