【题解】P6327 区间加区间 sin 和

题目内容

题目链接

给出一个长为 \(n\) 的整数序列 \(a\),支持两种操作:

  1. 给定 \(l,r,v\),将 \(a\) 中下标 \(\in[l,r]\) 的数全部加上 \(v\)

  2. 给定 \(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;
}
posted @ 2024-11-13 07:37  一位很会的教授er~  阅读(59)  评论(2)    收藏  举报