把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

luogu P6327 区间加区间sin和

题面传送门
sin和看上去很难维护。
但是如果你上过高一(大概?)的和差角公式就可以很轻松地解决。
\(\sin(a+x)=\sin a\cos x+\sin x\cos a\)
\(\cos(a+x)=\cos a\cos x-\sin a\sin x\)
写个结构体就可以用线段树维护了。
时间复杂度\(O(nlogn)\),目前最优解第四。
code:

#include<cstdio>
#include<cmath>
#define I inline
#define N 200039
#define l(x) x<<1
#define r(x) x<<1|1
using namespace std;
int n,m,k,x,y,z,op,a[N];
struct ques{
	double si,co;
	I void make(int x){si=sin(x);co=cos(x);}
	I int have(){return si!=0||co!=1;}
	ques operator +(const ques &s)const{return (ques){si+s.si,co+s.co};}
	ques operator *(const ques &s)const{return (ques){si*s.co+co*s.si,co*s.co-si*s.si};}
}f[N<<2],sum[N<<2],tmp,st=(ques){0,1};
I void up(int x){f[x]=f[l(x)]+f[r(x)];}
I void build(int l=1,int r=n,int now=1){
	sum[now]=st;if(l==r){f[now].make(a[l]);return;}int m=l+r>>1;
	build(l,m,l(now));build(m+1,r,r(now));up(now);
}
I void push(int x,ques w){f[x]=f[x]*w;sum[x]=sum[x]*w;}
I void pushdown(int x){sum[x].have()&&(push(l(x),sum[x]),push(r(x),sum[x]),sum[x]=st,0);}
I void get(int x,int y,ques w,int l=1,int r=n,int now=1){
	if(x<=l&&r<=y)return (void)(push(now,w));pushdown(now);int m=l+r>>1;
	(x<=m)&&(get(x,y,w,l,m,l(now)),0);(y>m)&&(get(x,y,w,m+1,r,r(now)),0);up(now);
}
I ques find(int x,int y,int l=1,int r=n,int now=1){
	if(x<=l&&r<=y) return f[now];int m=l+r>>1;pushdown(now);ques z=(ques){0,0};
	(x<=m)&&(z=z+find(x,y,l,m,l(now)),0);(y>m)&&(z=z+find(x,y,m+1,r,r(now)),0);return z;
}
int main(){
	freopen("1.in","r",stdin);
	register int i;scanf("%d",&n);
	for(i=1;i<=n;i++) scanf("%d",&a[i]);build();scanf("%d",&m);
	while(m--)scanf("%d%d%d",&op,&x,&y),(op^2)?(scanf("%d",&z),tmp.make(z),get(x,y,tmp),0):(printf("%.1lf\n",find(x,y).si));
}
posted @ 2021-04-09 21:07  275307894a  阅读(53)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end