【hihocoder 1723 子树统计】线性基

本文探讨了线性基的概念及其在异或运算下的应用,详细解释了如何使用高斯消元法求解线性基,特别是在树状数据结构中的实现。通过预处理每个节点的线性基大小,快速计算子树内节点异或和的所有可能值数量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先说一下自己对线性基及其求法的理解(有误的话请dalao指出鸭OrZ)
线性基,是线代里的那个东西吗?
是也不是,这里的线性基特指在异或运算下的基~
怎么求出来一个线性基呢?
先把线性基的集合设为空集,然后逐个加入元素。
如果待加入元素可以被集合中已有元素通过异或得出,则不加入,否则加入
那么,如何判断待加入元素可不可以被集合中已有元素异或得出呢?
传说中的高斯消元法!
我们可以维护一个对角矩阵(也就是只有主对角线上的元素为1啦),对于每次加入的元素a,进行如下操作:
如果a最高位的1已经有对应的行向量基(啊,我们在这里把一串二进制数看成行向量)了,那就用这个基异或a,重复操作直到a为0(不能插入)或a最高位的1没有对应的行向量,并把a插进去。
之后,要记得用a消去线性基集合中已有的a的最高位对应的位为1的,并消去可以消去的低位的1。

好啦,现在可以看题目啦~

给定一棵N个节点的有根树,树上每个节点有一个非负整数权重Wi。定义节点集合S={i1, i2, ……, ir}的总权重为:(⊕是异或运算)
treecnt1.png
每次询问一棵子树内所有可能出现的总权重数量,即令E为所询问的子树内节点的集合,
treecnt2.png
|T|即为可能出现的总权重数量。
Input
第一行包含两个整数N,Q,表示树的节点数目和询问数目,节点1总是这棵树的根部。
第二行包含N-1个整数,第i个整数Pi表示 i+1 号节点的父亲节点。数据保证 P i ≤ i P_i≤i Pii
第三行包含N个整数,表示每个节点的权重Wi。
第四行包含Q个整数,每个整数Qi表示询问子树Qi内的可能出现的总权重数量
N ≤ 100000 , Q ≤ 100000 , W i ≤ 260 N≤100000,Q≤100000,W_i≤260 N100000Q100000Wi260
Output
输出共Q行,每行包含一个整数T表示子树Qi内可能出现的总权重数量
Sample Input
7 3
1 2 2 1 5 5
8 4 3 1 2 4 6
2 5 1
Sample Output
8
4
16

大概就是给一棵树,然后每次给一个q,问以q为根的各种树的节点异或和结果有多少种。

预处理出来每个根的线性基的大小m,答案就是 2m


怎么预处理呢?

struct LineBasis{
    LL b[66];
    LL p[66];
    int cnt;
    LineBasis(){
        memset(b,0,sizeof(b));
        memset(p,0,sizeof(p));
        cnt = 0;
    }
    void Insert(LL val){
        for(int i=60;i>=0;i--){
            if((1LL<<i)&val){
                if(b[i] == 0){
                    b[i] = val;
                    break;
                }
                val ^= b[i];
            }
        }
        if(val > 0)
            cnt++;
    }
    LineBasis Merge(LineBasis n1,LineBasis n2){
        LineBasis ret = n1;
        for(int i=0;i<=60;i++)
            if(n2.b[i])
                ret.Insert(n2.b[i]);
        return ret;
    }
};

代码都来自SSimpLe_Y ~
看起来是不是非常正确,然后你需要一个dfs来调用这个东西~

void dfs(int x){
    for(int i=0;i<v[x].size();i++){
        int xx = v[x][i];
        dfs(xx);
        num[x] = num[x].Merge(num[x],num[xx]);
    }
    num[x].Insert(a[x]);
}

这样,只需要dfs(根节点),就可以获得所有结点的子树线性基啦!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值