生活随笔
收集整理的這篇文章主要介紹了
整数序列(牛客,线段树)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
鏈接: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)/~
總結
以上是生活随笔為你收集整理的整数序列(牛客,线段树)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。