題目描述
給出一個長度爲n的整數序列a1,a2,...,an,進行m次操作,操作分爲兩類。
操作1:給出l,r,v,將al,al+1,...,ar分別加上v;
操作2:給出l,r,詢問
輸入描述:
第一行一個整數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有點難操作。我們可以把每一個位置的數拆分成cos(a[i])+isin(a[i])
那麼當我們需要進行操作1的時候,我們只需要將那個數也拆成這樣進行乘法運算就行,然後我們最後查詢的時候我們只需要查區間的和的虛部就行。
Ps: real() 這個是實根
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<complex>
using namespace std;
const int maxn=2e5+10;
#define mem(a,b) memset(a,b,sizeof(a))
typedef complex<double> E;
int n,m,a[maxn];
E sum[maxn<<2],lz[maxn<<2];
void pushup(int k){
sum[k]=sum[k<<1]+sum[k<<1|1];
}
void pushdown(int k){
sum[k<<1]*=lz[k];lz[k<<1]*=lz[k];
sum[k<<1|1]*=lz[k];lz[k<<1|1]*=lz[k];
lz[k]=E(1,0);
}
void build(int l,int r,int k){
lz[k]=E(1,0);
if(l==r){
sum[k]=E(cos(a[l]),sin(a[l]));
return ;
}
int mid=(l+r)>>1;
build(l,mid,k<<1);build(mid+1,r,k<<1|1);
pushup(k);
}
void cha(int l,int r,int ql,int qr,E x,int k){
if(l==ql&&r==qr){
sum[k]*=x;
lz[k]*=x;
return ;
}
int mid=(l+r)>>1;
pushdown(k);
if(qr<=mid) cha(l,mid,ql,qr,x,k<<1);
else if(ql>mid) cha(mid+1,r,ql,qr,x,k<<1|1);
else cha(l,mid,ql,mid,x,k<<1),cha(mid+1,r,mid+1,qr,x,k<<1|1);
pushup(k);
}
double query(int l,int r,int ql,int qr,int k){
if(l==ql&&r==qr){
return sum[k].imag();
}
int mid=(l+r)>>1;
pushdown(k);
if(qr<=mid) return query(l,mid,ql,qr,k<<1);
else if(ql>mid) return query(mid+1,r,ql,qr,k<<1|1);
else return query(l,mid,ql,mid,k<<1)+query(mid+1,r,mid+1,qr,k<<1|1);
}
int main(){
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,n,1);
scanf("%d",&m);
while(m--){
int ki,u,v,w;
scanf("%d",&ki);
if(ki==1){
scanf("%d%d%d",&u,&v,&w);
cha(1,n,u,v,E(cos(w),sin(w)),1);
}
else{
scanf("%d%d",&u,&v);
printf("%.1lf\n",query(1,n,u,v,1));
}
}
return 0;
}