https://www.luogu.org/problem/P5524
看着能做就当线段树复健题了。
根据高中知识我们有
$sin(a+b)=sin(a)cos(b)+cos(a)sin(b)$
$cos(a+b)=cos(a)cos(b)-sin(a)sin(b)$
那这题只需要维护区间$sin$和与$cos$和的线段树就好了,完后区间加的更新方法如上。
但是比较卡常,建议标记永久化,并且减少求$sincos$的次数。(反正我开O2过了就不管了233)
~~我真的是连线段树都不会敲了我乱push结果RE了debug了半天,难受555~~
#include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; typedef double dl; const int N=2e5+5; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct tree{ dl s,c; ll w; }tr[N<<2]; int b[N]; inline void pushup(int a){ tr[a].s=tr[a<<1].s+tr[a<<1|1].s; tr[a].c=tr[a<<1].c+tr[a<<1|1].c; return; } inline void upd(int a,dl S,dl C){ dl s=tr[a].s,c=tr[a].c; tr[a].s=s*C+c*S; tr[a].c=c*C-s*S; return; } inline void pushdown(int a){ if(!tr[a].w)return; dl s=sin(tr[a].w),c=cos(tr[a].w); upd(a<<1,s,c);upd(a<<1|1,s,c); tr[a<<1].w+=tr[a].w;tr[a<<1|1].w+=tr[a].w; tr[a].w=0;return; } void build(int a,int l,int r){ if(l==r){ tr[a].s=sin(b[l]);tr[a].c=cos(b[l]);return; } int mid=(l+r)>>1; build(a<<1,l,mid);build(a<<1|1,mid+1,r); pushup(a); } void add(int a,int l,int r,int l1,int r1,int v){ if(r<l1||r1<l)return; if(l1<=l&&r<=r1){ upd(a,sin(v),cos(v));tr[a].w+=v;return; } int mid=(l+r)>>1;pushdown(a); add(a<<1,l,mid,l1,r1,v);add(a<<1|1,mid+1,r,l1,r1,v); pushup(a); } dl qry(int a,int l,int r,int l1,int r1){ if(r<l1||r1<l)return 0; if(l1<=l&&r<=r1)return tr[a].s; int mid=(l+r)>>1;pushdown(a); return qry(a<<1,l,mid,l1,r1)+qry(a<<1|1,mid+1,r,l1,r1); } int main(){ int n=read(); for(int i=1;i<=n;i++)b[i]=read(); build(1,1,n); int m=read(); while(m--){ int op=read(),l=read(),r=read(); if(op==1){ int v=read(); add(1,1,n,l,r,v); }else printf("%.1lf ",qry(1,1,n,l,r)); } return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++