先挖坑:
1.fhq treap
2.左偏树(可持久化可并堆)
3.重量平衡树。
4.拟阵。
1
维护一个序列,支持:
1.单点修改。
2.区间翻转。
3.给定
[
l
,
r
]
,
[l,r],
[l,r], 执行
s
w
a
p
(
a
i
,
a
i
+
1
)
,
s
w
a
p
(
a
i
+
2
,
a
i
+
3
)
.
.
.
swap(a_i,a_{i+1}) ,\space swap(a_{i+2},a_{i+3})...
swap(ai,ai+1), swap(ai+2,ai+3)...
4.区间求和。
用两棵平衡树分别维护奇数位置和偶数位置。swap操作就是把对应奇数位置的平衡树和偶数位置的平衡树交换。
线性基
参考自:https://blog.csdn.net/qaq__qaq/article/details/53812883
eg:
给定 n n n 个整数(数字可能重复),求在这些数中选取任意个,能否异或得到某个数。
思考这样一种能贪心:如果要查询一个数能不能被一些数异或得到,那么如果这些数最高位的 1 1 1 位置都不同,那么我们就可以贪心地去异或。线性基就维护了这样的数的集合。显然,其中只有 l o g log log 个数。
性质:
1.线性基中元素互相
x
o
r
xor
xor 所形成的异或集合,等价于原数集的元素互相
x
o
r
xor
xor 形成的异或集合。
2.线性基的异或集合中每个元素的异或方案唯一。
3.如果线性基是满的,它的异或集合为
[
1
,
2
n
−
1
]
[1,2n−1]
[1,2n−1]。
维护
我们设 a i a_i ai为最高位的1在第i位上的元素是什么。
插入
如果我们要插入,我们从高到低扫描它的二进制位 i i i。如果 a i a_i ai 不存在,那么令 a i a_i ai 等于 x x x,否则 x = x x o r a i x=x~xor~a_i x=x xor ai 如果 x x x 变成了 0 0 0,那么退出。
void insert(int x)
{
for(int i=32;i>=0;i--)
{
if(x&(1<<i))
{
if(!a[i])
{
a[i]=x;
break;
}
x^=a[i];
}
}
}
查询
存在性
如果要查询 x x x 能不能被异或出来,那么从高到低扫描 x x x 为 1 1 1 的二进制位 i i i, x = x x o r a i x=x~xor~a_i x=x xor ai 。如果 x x x 变成了 0 0 0,那么说明 x x x 能被异或出来。
最大值
从高位到低位扫描线性基里的元素,如果异或以后使得答案变大,那么就异或它。
long long get_max()
{
int ans=0;
for(int i=32;i>=0;i--)
if((ans&a[i])>ans) ans^=a[i];
return ans;
}
最小值
最小值就是最低位上的元素。
k小值
我们将线性基改造为每一位相互独立。
如果
i
<
j
i<j
i<j,
a
j
a_j
aj 的第
i
i
i 位是
1
1
1,那么将
a
j
a_j
aj 异或上
a
i
a_i
ai 。
这样,对于,二进制的某一位
i
i
i,只有
a
i
a_i
ai 的这一位是
1
1
1,其余都是
0
0
0.
查询的时候把
k
k
k 二进制拆分,如果第
i
i
i 位是
1
1
1,就异或上
a
i
a_i
ai。
( r e b u i l d rebuild rebuild 应该可以在插入的时候做,省掉一个 l o g log log )
void rebuild()
{
cnt=0;
for (int i=32;i>=0;i--)
for (int j=i-1;j>=0;j--)
if (a[i]&(1<<j))
a[i]^=a[j];
for (int i=0;i<=32;i++)
if (a[i])
p[cnt++]=a[i];
}
int query(int k)
{
int ans=0;
if (k>=(1<<cnt))
return -1;
for (int i=32;i>=0;i--)
if (k&(1<<i)) ans^=p[i];
return ret;
}
2
给定一个长度为
n
n
n 的序列,每个位置有一个数
a
[
i
]
a[i]
a[i]
多次询问
l
,
r
,
x
l,r,x
l,r,x,问能否用
[
l
,
r
]
[l,r]
[l,r] 的数使用异或凑出
x
x
x
n
≤
5
×
1
0
5
,
a
[
i
]
≤
1
0
9
n≤5×10^5,a[i]≤10^9
n≤5×105,a[i]≤109
异或凑数具有拟阵性质。
离线,把询问挂到右端点,扫到右端点的时候回答询问。
如果一些变量线性相关,那么删去其中较小的元素。
看看能表示这个数的最小元素是不是小于l
和生成树很像啊。
3
维护 n n n 个栈,支持区间压栈,区间弹栈,询问某个栈里的第 k k k 个元素
维护一颗关于时间的线段树
对于每个操作
[
l
,
r
]
[l,r]
[l,r],让他在
l
l
l 生效
r
+
1
r+1
r+1 失效
用时间线段树维护每个操作的影响,回答询问。
zjoi2016 大森林
重量平衡树
什么是重量平衡树?
为了维护一个平衡树,在插入/删除操作之后,为了保持树的平衡而重构的子树大小为均摊/期望
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
比如:替罪羊树,treap。
动态下标(毒瘤卡常技巧)
平衡树上判断两个点的前后是一个
l
o
g
log
log 的。
怎么更快地做这件事呢?
给每个点一个标号,
d
f
s
dfs
dfs 序上靠前的标号小。
设一个节点
x
x
x 对应的区间是 $ [l, r]$,令它的标号为
m
i
d
=
(
l
+
r
)
/
2
mid=(l+r)/2
mid=(l+r)/2。
让它的左右儿子对应的区间为
[
l
,
m
i
d
]
[l,mid]
[l,mid] 和
[
m
i
d
,
r
]
[mid,r]
[mid,r]。
然后递归计算标号。
但是树的深度不能很大,不然会炸精度。
所以用重量平衡树做这个东西
4
插入一个数,询问区间第 k k k 大。
平衡树套平衡树,动态维护下标。