Bessie and the cows are playing with sequences and need your help. They start with a sequence, initially containing just the number 0, and perform n operations. Each operation is one of the following:
- Add the integer xi to the first ai elements of the sequence.
- Append an integer ki to the end of the sequence. (And hence the size of the sequence increases by 1)
- Remove the last element of the sequence. So, the size of the sequence decreases by one. Note, that this operation can only be done if there are at least two elements in the sequence.
After each operation, the cows would like to know the average of all the numbers in the sequence. Help them!
The first line contains a single integer n (1 ≤ n ≤ 2·105) — the number of operations. The next n lines describe the operations. Each line will start with an integer ti (1 ≤ ti ≤ 3), denoting the type of the operation (see above). If ti = 1, it will be followed by two integersai, xi (|xi| ≤ 103; 1 ≤ ai). If ti = 2, it will be followed by a single integer ki (|ki| ≤ 103). If ti = 3, it will not be followed by anything.
It is guaranteed that all operations are correct (don't touch nonexistent elements) and that there will always be at least one element in the sequence.
Output n lines each containing the average of the numbers in the sequence after the corresponding operation.
The answer will be considered correct if its absolute or relative error doesn't exceed 10 - 6.
5
2 1
3
2 3
2 1
3
0.500000
0.000000
1.500000
1.333333
1.500000
6
2 1
1 2 20
2 2
1 2 -3
3
3
0.500000
20.500000
14.333333
12.333333
17.500000
17.000000
In the second sample, the sequence becomes
吐槽:此题虐得我够惨的。看到这样的题目,第一时间想到了线段树成段更新,由于题中数的长度可增可减,开始时建一颗足够大的树就好了,顺带记录下当前数列中的最后一个元素,用来完成第三种操作。最后到了test 10,死活过不去,返回结果是有个数据结果误差0.0000012...在Codeforces讨论区里也看到了其他人类似的反应。(线段树是可做的,只是不知道哪里细节出了问题。)于是,看了大神的思路,不得不叹服。
思路:没必要用到线段树,实现代码其实可以很短。首先用一个数组last[]记录当前数列最后一个元素的初始值,其中下标表示该数的位置。对于1操作,首先更新sum的值,然后用一个数组add记录这个更新是截止到哪里的,也就是对于输入的a,x, 则表示截止到a,说明从1 - a这一段都是更新过的,于是将add[a] += x,把这一操作记录起来。对于操作2,输入k后,也是先更新sum的值,然后将last的下标右移一格(因为增加了元素,长度+1),且last[pos] = k,也就是上面说到的“记录初始值”。关键在于3操作,因为要移除最后一个元素,而当前长度是pos,此时更新sum的值为 sum = sum - (last[pos]+add[pos]),现在知道add[]的用处了吧?之前新增的末尾元素可能在随后也在1操作的更新区间里,有了add[]就知道他被增加了多少了。然后清空last[pos],同时进行add[pos-1] += add[pos](因为根据add[]的定义,如果更新区间时更新到了pos,则pos-1也肯定在那个范围内,做一步操作是因为此时pos-1成为了数列中的最后一个元素,为后续操作做准备);最后将pos --,数列长度减1。还有sum要用__int64,否则会溢出。
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define MAX 200005 5 6 using namespace std; 7 8 int add[MAX],last[MAX]; 9 int n,t,a,x,k; 10 11 int main() 12 { 13 for(int i=0; i<MAX; i++) 14 add[i] = last[i] = 0; 15 int pos = 1; 16 __int64 sum = 0; 17 last[pos] = 0; 18 scanf("%d",&n); 19 while(n--) 20 { 21 scanf("%d",&t); 22 if(t == 1) 23 { 24 scanf("%d%d",&a,&x); 25 sum += a * x; 26 add[a] += x; 27 } 28 if(t == 2) 29 { 30 scanf("%d",&k); 31 sum += k; 32 last[++pos] = k; 33 } 34 if(t == 3) 35 { 36 sum -= (last[pos] + add[pos]); 37 add[pos - 1] += add[pos]; 38 add[pos] = last[pos] = 0; 39 pos --; 40 } 41 double ans = sum*1.0/pos; 42 printf("%.6lf\n",ans); 43 } 44 }