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