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

先挖坑:
1.fhq treap
2.左偏树(可持久化可并堆)
3.重量平衡树。
4.拟阵。

1

维护一个序列,支持:
1.单点修改。
2.区间翻转。
3.给定 [ l , r ] , 执行 s w a p ( a i , a i + 1 ) ,   s w a p ( a i + 2 , a i + 3 ) . . .
4.区间求和。

用两棵平衡树分别维护奇数位置和偶数位置。swap操作就是把对应奇数位置的平衡树和偶数位置的平衡树交换。

线性基

参考自:https://blog.csdn.net/qaq__qaq/article/details/53812883

eg:

给定 n 个整数(数字可能重复),求在这些数中选取任意个,能否异或得到某个数。

思考这样一种能贪心:如果要查询一个数能不能被一些数异或得到,那么如果这些数最高位的 1 位置都不同,那么我们就可以贪心地去异或。线性基就维护了这样的数的集合。显然,其中只有 l o g 个数。

性质:

1.线性基中元素互相 x o r 所形成的异或集合,等价于原数集的元素互相 x o r 形成的异或集合。
2.线性基的异或集合中每个元素的异或方案唯一。
3.如果线性基是满的,它的异或集合为 [ 1 , 2 n 1 ]

维护

我们设 a i 为最高位的1在第i位上的元素是什么。

插入

如果我们要插入,我们从高到低扫描它的二进制位 i 。如果 a i 不存在,那么令 a i 等于 x ,否则 x = x   x o r   a i 如果 x 变成了 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 1 的二进制位 i x = x   x o r   a i 。如果 x 变成了 0 ,那么说明 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 a j 的第 i 位是 1 ,那么将 a j 异或上 a i
这样,对于,二进制的某一位 i ,只有 a i 的这一位是 1 ,其余都是 0 .
查询的时候把 k 二进制拆分,如果第 i 位是 1 ,就异或上 a i

( r e b u i l d 应该可以在插入的时候做,省掉一个 l o g )

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 的序列,每个位置有一个数 a [ i ]
多次询问 l , r , x ,问能否用 [ l , r ] 的数使用异或凑出 x
n 5 × 10 5 , a [ i ] 10 9

异或凑数具有拟阵性质。
离线,把询问挂到右端点,扫到右端点的时候回答询问。
如果一些变量线性相关,那么删去其中较小的元素。
看看能表示这个数的最小元素是不是小于l

和生成树很像啊。

3

维护 n 个栈,支持区间压栈,区间弹栈,询问某个栈里的第 k 个元素

维护一颗关于时间的线段树
对于每个操作 [ l , r ] ,让他在 l 生效 r + 1 失效
用时间线段树维护每个操作的影响,回答询问。
zjoi2016 大森林

重量平衡树

什么是重量平衡树?
为了维护一个平衡树,在插入/删除操作之后,为了保持树的平衡而重构的子树大小为均摊/期望 O ( n l o g n )
比如:替罪羊树,treap。

动态下标(毒瘤卡常技巧)

平衡树上判断两个点的前后是一个 l o g 的。
怎么更快地做这件事呢?
给每个点一个标号, d f s 序上靠前的标号小。
设一个节点 x 对应的区间是 [ l , r ] ,令它的标号为 m i d = ( l + r ) / 2
让它的左右儿子对应的区间为 [ l , m i d ] [ m i d , r ]
然后递归计算标号。

但是树的深度不能很大,不然会炸精度。
所以用重量平衡树做这个东西

4

插入一个数,询问区间第 k 大。

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

猜你喜欢

转载自blog.csdn.net/DT_Kang/article/details/80374406