线性基+树上倍增 ---- BZOJ4568[线性基+树上倍增]

题目链接


题目大意:就是给你一棵树,每个树上的节点都有一个权值,现在给你一个询问u和v问你这个路径上面挑任意几个数进行xor运算,问你xor最大值是多少


解题思路:对于每个点我们可以维护它向根节点上面走 2 i 2^i 2i次方步数的线性基的信息那么我们就可以在查询的时候往上跳,边跳边合并


#include<bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define _for(i,a,b) for( int i = (a); i < (b); ++i)
#define _rep(i,a,b) for( int i = (a); i <= (b); ++i)
#define for_(i,a,b) for( int i = (a); i >= (b); -- i)
#define rep_(i,a,b) for( int i = (a); i > (b); -- i)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define hash Hash
#define next Next
#define pb push_back
#define f first
#define s second
#define y1 Y
using namespace std;
const int N = 2e4 + 10, mod = 1e9 + 7;
const int maxn = 2e4 + 10;
const int MAXL = 61;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
const int BUF=30000000;
char Buf[BUF],*buf=Buf;
template<typename T> void read(T &a)
{
    for(a=0;*buf<48;buf++);
    while(*buf>47) a=a*10+ *buf++ -48;
}
template<typename T, typename... Args> void read(T &first, Args& ... args) 
{
   read(first);
   read(args...);
}
ll node[maxn];
vector<int> G[maxn];
int n, q;

struct LinearBasis
{
   
    long long a[MAXL + 1];

    LinearBasis(){fill(a, a + MAXL + 1, 0);}
    LinearBasis(long long *x, int n) {build(x, n);}

    void init() {ms(a,0);}
    
    void insert(long long t) {
        for (int j = MAXL; j >= 0; j--) {
            if (!t) return;
            if (!(t & (1ll << j))) continue;

            if (a[j]) t ^= a[j];
            else {
                for (int k = 0; k < j; k++) if (t & (1ll << k)) t ^= a[k];
                for (int k = j + 1; k <= MAXL; k++) if (a[k] & (1ll << j)) a[k] ^= t;
                a[j] = t;
                break;
            }
        }
    }

    void build(long long *x, int n) {
        fill(a, a + MAXL + 1, 0);
        for (int i = 1; i <= n; i++) {
            insert(x[i]);
        }
    }

    long long queryMax() {
        long long res = 0;
        for (int i = 0; i <= MAXL; i++) res ^= a[i];
        return res;
    }

    void mergeFrom(const LinearBasis &other) {
        for (int i = 0; i <= MAXL; i++) insert(other.a[i]);
    }

    static LinearBasis merge(const LinearBasis &a, const LinearBasis &b) {
        LinearBasis res = a;
        for (int i = 0; i <= MAXL; i++) res.insert(b.a[i]);
        return res;
    }
}Mul[N][17];

int fa[N][17], depth[N];
inline void dfs(int u, int f) {
    fa[u][0] = f;depth[u] = depth[f] + 1;
    for(int i = 1; i <= 16; ++ i) 
      fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for(int i = 1; i <= 16; ++ i)
     Mul[u][i] = Mul[u][i].merge(Mul[u][i - 1],Mul[fa[u][i - 1]][i - 1]);
    for(auto it : G[u]) {
        if(it == f) continue;
        dfs(it,u);
    }
}

inline int LCA(int a, int b) {
    if(depth[a] > depth[b]) swap(a,b);
    int delta = depth[b] - depth[a];
    for(int i = 0; i <= 16; ++ i)
      if(delta >> i & 1) b = fa[b][i];
    if(a == b) return a;
    for(int i = 16; i >= 0; -- i)
      if(fa[a][i] != fa[b][i])
       a = fa[a][i], b = fa[b][i];
    return fa[a][0];
}

inline LinearBasis slove(int a, int b) {
    int delta = depth[a] - depth[b];
    LinearBasis res;
    for(int i = 0; i <= 16; ++ i) 
      if(delta >> i & 1) 
       res.mergeFrom(Mul[a][i]), a = fa[a][i];
    return res;
}

int main()
{
   fread(Buf,1,BUF,stdin);
   read(n,q);
   for(int i = 1; i <= n; ++ i) 
      read(node[i]),Mul[i][0].insert(node[i]);
   for(int i = 1; i < n; ++ i) {
      int l, r;
      read(l,r);
      G[l].push_back(r);
      G[r].push_back(l);
   }
    
   dfs(1,0);

   while(q --) {
       int l, r;
       read(l,r);
       int lca = LCA(l,r);
       LinearBasis res, ans;
       res.mergeFrom(slove(l,lca));
       ans.mergeFrom(slove(r,lca));
       res.mergeFrom(ans);
       res.mergeFrom(Mul[lca][0]);
       cout << res.queryMax() << "\n";
   }
   return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值