[2018.10.18 T3] 小 G 的線段樹

暫無鏈接

小 G 的線段樹

【題目描述】

小 G 是一名OIerOIer,他最近學習了一種高級數據結構——線段樹,
做題時,他遇到了如下的問題:
維護一個序列,要求支持三種操作:
1.區間加上一個數xx
2.區間賦值爲一個數xx
3.求一個區間的和
小 G 是一個愛思考的同學。他在做出來了這題之後,又提出了一個新的問題:如果把所有的操作隨機打亂,那麼每個詢問的期望輸出是多少呢?注意,隨機打亂既所有m!m!種操作排列的出現概率均等。爲了方便,我們假設詢問在最後且不參與隨機打亂。
考慮到精度問題,只要你的答案和標程答案的相對誤差不超過1e81e-8就算正確。

【輸入格式】

第一行三個整數n m qn\ m\ q,分別表示序列長度、修改數和詢問數接下來一行nn個整數aia_i,表示序列的初始值接下來mm行,每行44個整數c,l,r,xc,l,r,x
c=1c=1,則表示把區間[l,r][l,r]的元素加上xx
c=2c=2,則表示把區間[l,r][l,r]的元素全賦爲xx
接下來qq行,每行22個整數l,rl,r,代表每次詢問的左右端點。

【輸出格式】

qq行,每行一個實數,按照輸入順序分別爲qq個詢問的期望答案
答案保留 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

【數據範圍與約定】

對於30%30\%的數據,n<=10,m<=10n<=10,m<=10
對於60%60\%的數據,n<=1000,m<=1000n<=1000,m<=1000
對於另外10%10\%的數據,沒有操作11
對於另外10%10\%的數據,q=1q=1
對於100%100\%的數據,n,m,q<=1000001<=ai<=100000n,m,q<=100000,1<=a_i<=10000011操作中的
x<=100x<=10022操作中的x<=100000x<=100000

【提示】

離散型隨機變量的一切可能取值xix_i與其對應的概率pip_i的乘積之和稱爲該離散型隨機變量的期望,即E(x)=i=1nxipiE(x)=\sum_{i=1}^nx_ip_i

題解

先考慮如何計算單點的答案:

首先,該點的初始值只在無賦值操作的時候有效;考慮nn個賦值操作將整個操作序列分成了n+1n+1份,只有最後一個賦值操作有效,所以賦值操作對答案的貢獻爲xn\frac{x}{n};只有在最後一個賦值操作之後的加操作有效,所以加操作對答案的貢獻爲xn+1\frac{x}{n+1}

我們只需要查分統計每個點的賦值操作個數、賦值與加操作權值即可。

代碼
#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();}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章