写篇博客纪念一下人生第一道(YnOI)
不过这个题确实是不复杂
Description
支持两种操作,区间加和区间 (sin) 和
(n,m le 2 imes 10^5)
Solution
[Begin
]
我们看到三角函数,还有加法
还是比较明显地指向了和角公式
如果不会和角公式? 这个百度应该可以 $ Get $ 到
(sin(a+b)=sin(a) cos(b)+cos(a)sin(b))
(cos(a+b)=cos(a)cos(b)-sin(a)sin(b))
(sin) 和 (cos) 的都用库里的函数就行
我们维护一下每个点的 (sin) 和 (cos) 就可以了吧……
具体要这么写:
inline void push_up(int p,double ts,double tc)
{
double s=sinn(p),c=coss(p);
sinn(p)=ts*c+tc*s;
coss(p)=tc*c-ts*s;
return ;
}
inline void spread(int p)
{
if(fl(p))
{
fl(p<<1)+=fl(p); fl(p<<1|1)+=fl(p);
double ts=sin(fl(p)),tc=cos(fl(p));
push_up(p<<1,ts,tc); push_up(p<<1|1,ts,tc);
}return fl(p)=0,void();
}
(但是在其它函数里面是直接搞的左右和,没有用 (Push_up) )
[Q.A.D.
]
(P.S.)博主知道是(QED)
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
inline int read()
{
int res=0,f=1; char k;
while(!isdigit(k=getchar())) if(k=='-') f=-1;
while(isdigit(k)) res=res*10+k-'0',k=getchar();
return res*f;
}
const int N=2e5+10;
struct node{
int l,r,fl;
double sinn,coss;
#define fl(p) t[p].fl
#define l(p) t[p].l
#define r(p) t[p].r
#define sinn(p) t[p].sinn
#define coss(p) t[p].coss
}t[N<<2];
int n,a[N];
inline void build(int p,int l,int r)
{
l(p)=l; r(p)=r;
if(l==r) return sinn(p)=sin(a[l]),coss(p)=cos(a[l]),void();
int mid=(l+r)>>1;
build(p<<1,l,mid); build(p<<1|1,mid+1,r);
sinn(p)=sinn(p<<1)+sinn(p<<1|1); coss(p)=coss(p<<1|1)+coss(p<<1);
return ;
}
inline void push_up(int p,double ts,double tc)
{
double s=sinn(p),c=coss(p);
sinn(p)=ts*c+tc*s;
coss(p)=tc*c-ts*s;
return ;
}
inline void spread(int p)
{
if(fl(p))
{
fl(p<<1)+=fl(p); fl(p<<1|1)+=fl(p);
double ts=sin(fl(p)),tc=cos(fl(p));
push_up(p<<1,ts,tc); push_up(p<<1|1,ts,tc);
}return fl(p)=0,void();
}
inline void change(int p,int l,int r,double sinn,double coss,int x)
{
if(l<=l(p)&&r(p)<=r) return push_up(p,sinn,coss),fl(p)+=x,void();
int mid=(l(p)+r(p))>>1; spread(p);
if(l<=mid) change(p<<1,l,r,sinn,coss,x);
if(r>mid) change(p<<1|1,l,r,sinn,coss,x);
sinn(p)=sinn(p<<1)+sinn(p<<1|1);
coss(p)=coss(p<<1|1)+coss(p<<1);
return ;
}
inline double ask(int p,int l,int r)
{
if(l<=l(p)&&r(p)<=r) return sinn(p);
spread(p);
int mid=(l(p)+r(p))>>1; double ans=0;
if(l<=mid) ans+=ask(p<<1,l,r);
if(r>mid) ans+=ask(p<<1|1,l,r);
return ans;
}
signed main()
{
n=read(); for(int i=1;i<=n;++i) a[i]=read();
build(1,1,n); int T=read();
while(T--)
{
int opt=read(),x=read(),y=read(),z;
if(opt==1) z=read(),change(1,x,y,sin(z),cos(z),z);
if(opt==2) printf("%.1lf
",ask(1,x,y));
}
return 0;
}
}
signed main(){return yspm::main();}