洛谷 P6327 区间加区间sin和
洛谷 P6327 区间加区间sin和
题目描述
给出一个长度为 nn 的整数序列 a_1,a_2,\ldots,a_na1,a2,…,a**n,进行 mm 次操作,操作分为两类。
操作 11:给出 l,r,vl,r,v,将 a_l,a_{l+1},\ldots,a_ra**l,a**l+1,…,a**r 分别加上 vv。
操作 22:给出 l,rl,r,询问 \sum\limits_{i=l}^{r}\sin(a_i)i=l∑rsin(a**i)。
输入格式
第一行一个整数 nn。
接下来一行 nn 个整数表示 a_1,a_2,\ldots,a_na1,a2,…,a**n。
接下来一行一个整数 mm。
接下来 mm 行,每行表示一个操作,操作 11 表示为 1 l r v
,操作 22 表示为 2 l r
。
输出格式
对每个操作 22,输出一行,表示答案,四舍五入保留一位小数。
保证答案的绝对值大于 0.10.1,且答案的准确值的小数点后第二位不是 44 或 55。
题解:
看到区间带修就想线段树啊。但是这道题怎么维护加权之后的sin值呢?
这就需要用到高一学的三角函数的和差角函数。
和差角函数不会的请走百度百科。
所以线段树维护一个cos值一个sin值,在打lazy标记的时候把两个值同时更新,就可以得到正确答案啦。
剩下的就是裸的线段树。
关于线段树,不会的可以走:简单线段树知识点详解
如同部分题目不开longlong见祖宗一样。这道题也需要double,注意精度损失。
代码:
#include<cstdio>
#include<cmath>
#define lson pos<<1
#define rson pos<<1|1
using namespace std;
const int maxn=2e5+5;
int n,m;
double a[maxn];
double cs[maxn<<2],sn[maxn<<2];
double lazy[maxn<<2];
void build(int pos,int l,int r)
{
int mid=(l+r)>>1;
if(l==r)
{
sn[pos]=sin(a[l]);
cs[pos]=cos(a[l]);
return;
}
build(lson,l,mid);
build(rson,mid+1,r);
sn[pos]=sn[lson]+sn[rson];
cs[pos]=cs[lson]+cs[rson];
}
void mark(int pos,int l,int r,double k)
{
double snn=sn[pos],css=cs[pos];
sn[pos]=(snn*cos(k)+css*sin(k));
cs[pos]=(css*cos(k)-snn*sin(k));
lazy[pos]+=k;
}
void pushdown(int pos,int l,int r)
{
int mid=(l+r)>>1;
mark(lson,l,mid,lazy[pos]);
mark(rson,mid+1,r,lazy[pos]);
lazy[pos]=0;
}
void update(int pos,int l,int r,int x,int y,double k)
{
int mid=(l+r)>>1;
if(x<=l && r<=y)
{
mark(pos,l,r,k);
return;
}
if(lazy[pos])
pushdown(pos,l,r);
if(x<=mid)
update(lson,l,mid,x,y,k);
if(y>mid)
update(rson,mid+1,r,x,y,k);
sn[pos]=sn[lson]+sn[rson];
cs[pos]=cs[lson]+cs[rson];
}
double query(int pos,int l,int r,int x,int y)
{
double ret=0;
int mid=(l+r)>>1;
if(x<=l && r<=y)
return sn[pos];
if(lazy[pos])
pushdown(pos,l,r);
if(x<=mid)
ret+=query(lson,l,mid,x,y);
if(y>mid)
ret+=query(rson,mid+1,r,x,y);
return ret;
}
int main()
{
// freopen("gold.in","r",stdin);
// freopen("gold.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%lf",&a[i]);
build(1,1,n);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
int opt,x,y;
double v;
scanf("%d%d%d",&opt,&x,&y);
if(opt==1)
{
scanf("%lf",&v);
update(1,1,n,x,y,v);
}
else
printf("%.1lf\n",query(1,1,n,x,y));
}
return 0;
}