zoukankan      html  css  js  c++  java
  • [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;
        }
    }
    
    
  • 相关阅读:
    go module基本使用
    jquery的radio的change事件
    etcd 快速入门
    linux下查看php-fpm是否开启以及如何开启
    js 获取某年的某天是第几周
    gland go list-m:无法识别的导入路径
    Xshell连接有跳板机(堡垒机)的服务器
    PHP中时间戳和时区
    SQL分页过多时, 如何优化
    MySQL语句的优化
  • 原文地址:https://www.cnblogs.com/mollnn/p/13139119.html
Copyright © 2011-2022 走看看