coin(GZOI2024 Day1 T3)
题目大意
给你 \(n\) 个硬币,每个硬币有属性 \(a_i,b_i,p_i\),表示有 \(p_i\) 的概率值为 \(a_i\),有 \(1-p_i\) 的概率值为 \(b_i\)。所有的 \(a_i\) 所有的 \(b_i\) 均不同。有 \(q\) 次询问,询问有两种:
- 给定 \(l,r,k\),问 \([l,r]\) 的硬币值都 \(<\) 第 \(k\) 个硬币的值的概率是多少。
- 给定 \(x,a,b,p\),把第 \(x\) 个硬币修改成 \(a,b,p\)。
做法1 线段树
假设 \(a_i<b_i\),可以把第 \(k\) 的硬币分别计算 \(a_k,b_k\),算两次,答案按照概率相加。设第 \(k\) 个硬币的值为 \(x\),在 \(i\in[l,r]\) 且 \(i\not =k\),若:
- 存在 \(x<a_i\),则 \(ans=0\)。(无论怎么去取,第 \(i\) 个硬币都比 \(x\) 大)
- \(b_i<x \Rightarrow ans\times 1\)(无论怎么去取,第 \(i\) 个硬币都比 \(x\) 小)
- \(a_i<x<b_i \Rightarrow ans\times p_i\)
所以如果 \([l,r]\) 存在 \(x<a_i\) 答案为 \(0\),这个很好判断。
否则答案是 \(\prod_{i=l}^r p_i[x<b_i]\)。
维护一颗线段树,每个节点表示一个区间。答案就是 \(\log\) 个区间的答案相加。
每个区间我们要取 \(b_i>x\) 的答案,考虑对线段树每个节点再维护一个数组,把 \(b_i\) 排序。做个前缀或者后缀积,询问时二分一下。不考虑修改时间复杂度 \(O(n\log^2n)\),空间 \(O(n\log n)\)。
修改时是单点修改。显然数组不好单点删除和插入,同时维护有序和前或后缀积。
考虑到每次修改只会涉及到线段树上 \(\log\) 个节点,我们把修改离线,加入那 \(\log\) 个数组的下标,要进行单点修改和前后缀积的操作,维护树状数组即可,空间仍然是 \(O(n\log n)\) 的,时间仍然是 \(O(n\log^2n)\)。
注意树状数组还需维护有多少个 \(0\),没有 \(0\) 才能计入答案。
总的来说,就是线段树套树状数组,离线询问离散化,优化空间。
做法2 分块
\(0\) 是好维护的,这里忽略不讲。
每个块按 \(b\) 排序,维护前缀积。
对于询问,整块进行二分定位,乘起来,散块暴力合并,时间 \(O(T+\frac{n}{T}\log T)\)。
对于修改,重构块,时间复杂度是 \(O(T)\)。
总的时间复杂度是 \(O(q(T+\frac{n}{T}\log T))=O(q(T+\frac{n}{T}\log N))\ge O(q\sqrt{N\log N})\)
\(T=\sqrt{N \log N}\) 时,时间复杂度最小,为 \(O(q\sqrt{N\log N})\)。
感觉分块更好写
精度的坑
虽然输入只有四位小数,但是可能因为二进制存小数位的问题,在输入时就会掉精度,如 \(0.0003\) 会变成 \(0.0002999 \dots 9997\)。解决办法时用 \(char\) 输入,或者乘上 \(10000\) 后四舍五入一下。
另一个比较常识的坑是小数按整型输出会直接抹掉小数位,不是四舍五入。
标签:GZOI2024,log,线段,T3,修改,数组,维护,coin,复杂度 From: https://www.cnblogs.com/liyixin0514/p/18403935