【hihocoder 1723 子樹統計】線性基

先說一下自己對線性基及其求法的理解(有誤的話請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 號節點的父親節點。數據保證PiiP_i≤i
第三行包含N個整數,表示每個節點的權重Wi。
第四行包含Q個整數,每個整數Qi表示詢問子樹Qi內的可能出現的總權重數量
N100000Q100000Wi260N≤100000,Q≤100000,W_i≤260
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(根節點),就可以獲得所有結點的子樹線性基啦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章