[2018.10.18 T3] 小 G 的線段樹
暫無連結
小 G 的線段樹
【題目描述】
小 G 是一名
,他最近學習了一種高階資料結構——線段樹,
做題時,他遇到了如下的問題:
維護一個序列,要求支援三種操作:
1.區間加上一個數
2.區間賦值為一個數
3.求一個區間的和
小 G 是一個愛思考的同學。他在做出來了這題之後,又提出了一個新的問題:如果把所有的操作隨機打亂,那麼每個詢問的期望輸出是多少呢?注意,隨機打亂既所有
種操作排列的出現概率均等。為了方便,我們假設詢問在最後且不參與隨機打亂。
考慮到精度問題,只要你的答案和標程答案的相對誤差不超過
【輸入格式】
第一行三個整數
,分別表示序列長度、修改數和詢問數接下來一行
個整數
,表示序列的初始值接下來
行,每行
個整數
若
,則表示把區間
的元素加上
若
,則表示把區間
的元素全賦為
接下來
行,每行
個整數
,代表每次詢問的左右端點。
【輸出格式】
行,每行一個實數,按照輸入順序分別為
個詢問的期望答案
答案保留 3 位小數
【樣例 1】
segment. in
5 4 8
2 3 3 3 3
1 1 3 2
1 3 5 1
2 2 4 1
2 1 3 4
1 1
2 2
3 3
4 4
5 5
1 3
2 5
1 5
segment.out
5.000
3.167
3.500
1.500
4.000
11.667
12.167
17.167
【樣例 2】
見選手目錄下 segment. in/segment.ans
【資料範圍與約定】
對於
的資料,
對於
的資料,
對於另外
的資料,沒有操作
對於另外
的資料,
對於
的資料,
,
操作中的
,
操作中的
。
【提示】
離散型隨機變數的一切可能取值 與其對應的概率 的乘積之和稱為該離散型隨機變數的期望,即 。
題解
先考慮如何計算單點的答案:
首先,該點的初始值只在無賦值操作的時候有效;考慮 個賦值操作將整個操作序列分成了 份,只有最後一個賦值操作有效,所以賦值操作對答案的貢獻為 ;只有在最後一個賦值操作之後的加操作有效,所以加操作對答案的貢獻為 。
我們只需要查分統計每個點的賦值操作個數、賦值與加操作權值即可。
程式碼
#include<cstdio>
const int M=1e5+5;
int tot1,tot2,n,m,q,que[M];
long long add[M],ass[M],cot[M];
double ans[M];
void in(){scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;++i)scanf("%d",&que[i]);}
void ac()
{
for(int i=1,op,l,r,x;i<=m;++i)
{
scanf("%d%d%d%d",&op,&l,&r,&x);
op==1?(add[l]+=x,add[r+1]-=x):(ass[l]+=x,ass[r+1]-=x,++cot[l],--cot[r+1]);
}
for(int i=1;i<=n;++i)add[i]+=add[i-1],ass[i]+=ass[i-1],cot[i]+=cot[i-1],ans[i]=add[i]/(cot[i]+1.0);
for(int i=1;i<=n;++i)ans[i]+=(cot[i]?1.0*ass[i]/cot[i]:que[i]);
for(int i=1;i<=n;++i)ans[i]+=ans[i-1];
for(int i=1,l,r;i<=q;++i)
scanf("%d%d",&l,&r),printf("%.3lf\n",ans[r]-ans[l-1]);
}
int main(){in(),ac();}