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));
}