题目大意
给定一个长度为 的整数数列 和 次操作:
修改操作:形如 1 x y,表示将 的值修改为 ;
询问操作:形如 2 x y,表示询问的值。
【40%】n,q<=5000
题目怎么说怎么做。
【另20%】所有询问的x=0
二进制总共只有20位,直接记录每一位为1的有多少个数,假设记为cnt[i]查询时,y的第i个二进制位为1,就答案加上。
【100%】n,q<=10^5
我们还是对于每个二进制位单独考虑,且y这一位为1才考虑。
不考虑+x时,我们还可以弄一棵值域线段树,那么cnt[i]所包含的数就是这样的:比i高的位任意,i位以内满足在 这个区间内。可以发现我们查询的区间对于整个值域来说并不连续,而是一段一段的,因此我们对每个二进制位都开一棵值域线段树,第i位的线段树存储的数则由 变为 。这样我们操作第i位时,直接在第i位的线段树中查询内的数有多少个,就行了。
接下来考虑+x。这个实际上是对查询区间的位移,比如当前查询区间,那么就变成。要注意这里的x是的。唯一的问题就是区间左端点可能为负。这好办,先把0到右端点的正常操作,假设左端点变成了,那我们再查询就行了。这里相当于是退位一样的东西。
代码
//我把线段树换成树状数组,这样常数小代码短
1 |
|
