zoukankan      html  css  js  c++  java
  • 查询出树上指定u到v上值异或和最大的值(线性基+倍增LCA)

    题:https://loj.ac/problem/2013

    题:https://www.luogu.com.cn/problem/P3292

    题意:给定n个节点的树,每个节点都有权值,q组查询[u, v]查询u到v的最短路径上的点权能组成的最大异或和;

    分析:朴素地想,肯定是每次u到v上的点全部塞到线性基中,然后找出最大值即可,但是朴素地TLE;

       因此我们可以利用树上找路径倍增求LCA,因为线性基的大小只有log级别,所以我们在处理倍增的时候顺便把向上祖先路径的线性基预处理一下;

       在solve时也顺理成章地合并“一段一段”的线性基即可。

    #include<bits/stdc++.h>
    using namespace std;
    #define pb push_back
    #define MP make_pair
    #define lson root<<1,l,midd
    #define rson root<<1|1,midd+1,r
    typedef long long ll;
    const int M=60;
    const int N=2e4+4;
    struct LB{
        ll a[M+2];
        void init(){ memset(a,0,sizeof(a)); }
        void Insert(ll x){
            for(int i=M;i>=0;i--){
                if(!(x&(1ll<<i))) continue;
                if(a[i])
                    x^=a[i];
                else{
                    for(int j=0;j<i;j++) if(x&(1ll<<j)) x^=a[j];
                    for(int j=i+1;j<=M;j++) if(a[j]&(1ll<<i)) a[j]^=x;
                    a[i]=x;
                    return ;
                }
            }
        }
        ll getmax(){
            ll res=0;
            for(int i=M;i>=0;i--) res=max(res,res^a[i]);
            return res;
        }
        LB operator + (const LB &other)const{
            LB res = *this;
            for(int i=0;i<=M;i++) if(other.a[i]) res.Insert(other.a[i]);
            return res;
        }
    }lb[N][15];
    int f[N][15],deep[N],lg[N];
    vector<int>g[N];
    ll val[N];
    void dfs(int u,int fa){
        deep[u]=deep[fa]+1;
        lb[u][0].init(); lb[u][0].Insert(val[u]);
        f[u][0]=fa;
        for(int i=1;i<=lg[deep[u]];i++){
            f[u][i]=f[f[u][i-1]][i-1];
            lb[u][i]=lb[u][i-1]+lb[f[u][i-1]][i-1];
        }
        for(auto v:g[u]) if(v!=fa) dfs(v,u);
    }
    ll solve(int u,int v){
        LB tmp; tmp.init();
        if(deep[u]<deep[v]) swap(u,v);
        while(deep[u]>deep[v]){
            tmp = tmp + lb[u][lg[deep[u]-deep[v]]-1];
            u=f[u][lg[deep[u]-deep[v]]-1];
        }
        if(u==v){
            tmp.Insert(val[u]);
            return tmp.getmax();
        }
        for(int i=lg[deep[u]]-1;i>=0;i--)
            if(f[u][i]!=f[v][i])
                tmp = tmp + lb[u][i] + lb[v][i], u=f[u][i], v=f[v][i];
        tmp.Insert(val[f[u][0]]);
        tmp.Insert(val[u]);
        tmp.Insert(val[v]);
        return tmp.getmax();
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&val[i]);
        for(int u,v,i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            g[u].pb(v),g[v].pb(u);
        }
        for(int i=1;i<=n;i++) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
        dfs(1,0);
        for(int u,v,i=1;i<=m;i++){
            scanf("%d%d",&u,&v);
            printf("%lld
    ",solve(u,v));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    荣誉追记
    通过代码实现 Windows Mobile 窗体的最小化 (转)
    软件协会周年庆(高清晰)
    菜鸟级注册与限制
    Ajax Tree (转)
    转职场别做愤青
    菜鸟级分页用户控件
    Windows Mobile 常用键值(VK)对应表及系统文件夹简单介绍
    12.Linux软件包管理相关操作
    5.Docker应用
  • 原文地址:https://www.cnblogs.com/starve/p/13812287.html
Copyright © 2011-2022 走看看