【5.18 提高班小记】数据结构&&线性基

先挖坑:
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,2n1]

维护

我们设 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 &lt; j i&lt;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 n5×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 大。

平衡树套平衡树,动态维护下标。

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值