[SCOI2016] 幸运数字

Description

给定一棵树,每个点有一个权值。有若干询问,每次给定一条简单路径,问这条路径上的所有点中,选择一部分异或起来,可以得到的最大值是多少。

Solution

首先显然可以暴力树剖,用线段树维护线性基,只是这样复杂度略高 (O(q log^4 n))

用树上倍增维护,可以将复杂度降到 (O(q log^3 n))

考虑到对两个区间进行合并时,重复部分并不会影响,所以可以借鉴 ST 表的思路,将复杂度降到 (O(n log^3 n + q log^2 n))

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 20005;
const int lgN = 15;

struct linear_base {
    int a[64];
    linear_base() {
        memset(a,0,sizeof a);
    }
    void insert(int k) {
        for(int j=63; j>=0; --j)
            if((k>>j)&1ll)
                if(a[j]==0) {a[j]=k;break;}
                else k^=a[j];
    }
    void join(linear_base x) {
        for(int i=63;i>=0;--i) {
            if(x.a[i]>0) insert(x.a[i]);
        }
    }
    int solve() {
        int ans = 0;
        for(int i=63; i>=0; --i)
            if((ans^a[i]) > ans) ans^=a[i];
        return ans;
    }
} lb[N][lgN+1];

vector <int> g[N];
int val[N],vis[N],t1,t2,t3,n,q,fa[N][lgN+1],dep[N];

void dfs(int p) {
    vis[p]=1;
    for(int q:g[p]) {
        if(vis[q]==0) {
            fa[q][0]=p;
            dep[q]=dep[p]+1;
            dfs(q);
        }
    }
}

void presolve() {
    for(int i=1;i<=n;i++) lb[i][0].insert(val[i]);
    for(int j=1;j<=lgN;j++) {
        for(int i=1;i<=n;i++) {
            fa[i][j]=fa[fa[i][j-1]][j-1];
            lb[i][j].join(lb[i][j-1]);
            lb[i][j].join(lb[fa[i][j-1]][j-1]);
        }
    }
}

int lca(int p,int q) {
    if(dep[p]<dep[q]) swap(p,q);
    for(int i=lgN;i>=0;--i) if(dep[fa[p][i]]>=dep[q]) p=fa[p][i];
    for(int i=lgN;i>=0;--i) if(fa[p][i]-fa[q][i]) p=fa[p][i],q=fa[q][i];
    if(p-q) return fa[p][0];
    return p;
}

linear_base linequery(int p,int l) {
    int len=dep[p]-dep[l]+1;
    int lglen=log2(len);
    linear_base ans;
    ans.join(lb[p][lglen]);
    int delta=len-(1ll<<lglen);
    for(int i=lgN;i>=0;--i) if(delta&(1<<i)) p=fa[p][i];
    ans.join(lb[p][lglen]);
    return ans;
}

int query(int p,int q) {
    int l=lca(p,q);
    linear_base tmp;
    tmp.join(linequery(p,l));
    tmp.join(linequery(q,l));
    return tmp.solve();
}

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>q;
    for(int i=1;i<=n;i++) cin>>val[i];
    for(int i=1;i<n;i++) {
        cin>>t1>>t2;
        g[t1].push_back(t2);
        g[t2].push_back(t1);
    }
    dep[1]=1;
    dfs(1);
    presolve();
    for(int i=1;i<=q;i++) {
        cin>>t1>>t2;
        cout<<query(t1,t2)<<endl;
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/13139119.html