1. 程式人生 > 實用技巧 >洛谷 P6327 區間加區間sin和

洛谷 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=lrsin(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;
}