洛谷 P6327 區間加區間sin和
阿新 • • 發佈:2020-11-23
洛谷 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; }