整数序列(牛客,线段树)

链接:https://ac.nowcoder.com/acm/contest/160/D
来源:牛客网

题目描述
给出一个长度为n的整数序列a1,a2,…,an,进行m次操作,操作分为两类。
操作1:给出l,r,v,将al,al+1,…,ar分别加上v;
操作2:给出l,r,询问\sum\limits_{i=l}^{r}sin(a_i)
i=l

r

sin(a
i

)
输入描述:
第一行一个整数n
接下来一行n个整数表示a1,a2,…,an
接下来一行一个整数m
接下来m行,每行表示一个操作,操作1表示为1 l r v,操作2表示为2 l r
保证1≤n,m,ai,v≤200000;1≤l≤r≤n,v是整数
输出描述:
对每个操作2,输出一行,表示答案,四舍五入保留一位小数
保证答案的绝对值大于0.1,且答案的准确值的小数点后第二位不是4或5
数据随机生成(n,m人工指定,其余整数在数据范围内均匀选取),并去除不满足条件的操作2
示例1
输入
复制
4
1 2 3 4
5
2 2 4
1 1 3 1
2 2 4
1 2 4 2
2 1 3
输出
复制
0.3
-1.4
-0.3
区间修改加区间sin求和。
别管是修改还是求和都得是区间操作。肯定不能到叶子节点。。当一个区间内都加了v,对于当前节点来说,sin(x+v)=sinxcosv+cosxsinv;cos(x+v)=cosxcosv-sinxsinv;
如果左右两个儿子节点都加了v,对于该节点来说,sum[cur]=sum[cur<<1]+sum[cur<<1|1]=sin(lx+v)+sin(rx+v)=cosv*(sinlx+sinrx)+sinv*(coslx+cosrx)。
这样一看,我们要维护两个之cos和sin。
代码如下:

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxx=2e5+100;
struct node{
	int l;
	int r;
	double ssin;
	double ccon;
	ll lazy;
}p[maxx<<2];
ll a[maxx];
int n,m;

inline void pushup(int cur)
{
	p[cur].ccon=p[cur<<1].ccon+p[cur<<1|1].ccon;
	p[cur].ssin=p[cur<<1].ssin+p[cur<<1|1].ssin;
}
inline void pushdown(int cur) 
{
    if(p[cur].lazy)
	{
        ll v = p[cur].lazy;
        p[cur<<1].lazy+=v;
        p[cur<<1|1].lazy+=v;
        double tsin=p[cur<<1].ssin,tcos=p[cur<<1].ccon;
        p[cur<<1].ssin=tsin*cos(v)+tcos*sin(v);
        p[cur<<1].ccon=tcos*cos(v)-tsin*sin(v);
        tsin=p[cur<<1|1].ssin,tcos=p[cur<<1|1].ccon;
        p[cur<<1|1].ssin=tsin*cos(v)+tcos*sin(v);
        p[cur<<1|1].ccon=tcos*cos(v)-tsin*sin(v);
        p[cur].lazy=0;
    }
}
inline void build(int l,int r,int cur)
{
	p[cur].l=l;
	p[cur].r=r;
	p[cur].ccon=p[cur].ssin=0.0;
	p[cur].lazy=0;
	if(l==r)
	{
		p[cur].ssin=sin(a[l]);
		p[cur].ccon=cos(a[l]);
		return ;
	}
	int mid=l+r>>1;
	build(l,mid,cur<<1);
	build(mid+1,r,cur<<1|1);
	pushup(cur);
}
inline void update(int l,int r,int cur,ll z)
{
	int L=p[cur].l;
	int R=p[cur].r;
	if(l<=L&&R<=r)
	{
		p[cur].lazy+=z;
		double tsin=p[cur].ssin,tcos=p[cur].ccon;//这里注意,一定要把之前的值给记录下来,否则会用更改之后的值。
		p[cur].ssin=cos(z)*tsin+sin(z)*tcos;
		p[cur].ccon=cos(z)*tcos-sin(z)*tsin;
		return ;
	}
	pushdown(cur);
	int mid=L+R>>1;
	if(r<=mid) update(l,r,cur<<1,z);
	else if(l>mid) update(l,r,cur<<1|1,z);
	else
	{
		update(l,mid,cur<<1,z);
		update(mid+1,r,cur<<1|1,z);
	}
	pushup(cur);
}
inline double query(int l,int r,int cur)
{
	int L=p[cur].l;
	int R=p[cur].r;
	if(l<=L&&R<=r) return p[cur].ssin;
	pushdown(cur);
	int mid=L+R>>1;
	if(r<=mid) return query(l,r,cur<<1);
	else if(l>mid) return query(l,r,cur<<1|1);
	else return query(l,mid,cur<<1)+query(mid+1,r,cur<<1|1);
	//pushup(cur);
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
	build(1,n,1);
	int op,l,r;ll z;
	scanf("%d",&m);
	while(m--)
	{
		scanf("%d%d%d",&op,&l,&r);
		if(op==1)
		{
			scanf("%lld",&z);
			update(l,r,1,z);
		}
		else printf("%.1f\n",query(l,r,1));
	}
	return 0;
}

努力加油a啊,(o)/~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值