zoukankan      html  css  js  c++  java
  • BZOJ

    题意:

      给出一颗带点权的树。q次询问,每次询问给出点u,v。在两点路径上选出一些点,使其点权异或和最大。

    题解:

      倍增的合并树上的线性基。对于每次询问,将路径上的点倍增的合并。最后贪心的从高位开始取最大值。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 2e4+10;
    int n, q, tot;
    int u, v;
    int head[N], to[N<<1], nxt[N<<1];
    int depth[N], fa[N][20];
    ll val, ans;
    ll dp[N][20][65], tt[65];
    void add(ll *a, ll b) {
        for(int i = 62; i >= 0; i--) if((1ll<<i)&b) {
            if(!a[i]) {
                a[i] = b;
                return ;
            }
            else b ^= a[i];
        }
    }
    void dfs(int x, int pre, int d) {
        fa[x][0] = pre;
        depth[x] = d;
        for(int i = head[x]; ~i; i = nxt[i]) if(to[i] != pre) dfs(to[i], x, d+1);
    }
    int main() {
        scanf("%d%d", &n, &q);
        memset(head, -1, sizeof(head));
        for(int i = 1; i <= n; i++) scanf("%lld", &val), add(dp[i][0], val);
        for(int i = 1; i < n; i++) {
            scanf("%d%d", &u, &v);
            to[++tot] = u; nxt[tot] = head[v]; head[v] = tot;
            to[++tot] = v; nxt[tot] = head[u]; head[u] = tot;
        }
        dfs(1, 0, 0);
        for(int i = 0; i < 16; i++) {
            for(int j = 1; j <= n; j++) {
                v = fa[j][i];
                fa[j][i+1] = fa[v][i];
                for(int k = 62; k >= 0; k--) {
                    add(dp[j][i+1], dp[j][i][k]);
                    add(dp[j][i+1], dp[v][i][k]);
                }
            }
        }
        while(q--) {
            ans = 0;
            memset(tt, 0, sizeof(tt));
            scanf("%d%d", &u, &v);
            if(depth[u]<depth[v]) swap(u, v);
            int k = depth[u]-depth[v];
            for(int i = 16; i >= 0; i--) {
                if(k&(1<<i)) {
                    for(int j = 62; j >= 0; j--) if(dp[u][i][j]) add(tt, dp[u][i][j]);
                    u = fa[u][i];
                }
            }
            for(int i = 16; i >= 0; i--) {
                if(fa[u][i] != fa[v][i]) {
                    for(int j = 62; j >= 0; j--) if(dp[u][i][j]) add(tt, dp[u][i][j]);
                    for(int j = 62; j >= 0; j--) if(dp[v][i][j]) add(tt, dp[v][i][j]);
                    u = fa[u][i]; v = fa[v][i];
                }
            }
            for(int j = 62; j >= 0; j--) if(dp[u][0][j]) add(tt, dp[u][0][j]);
            for(int j = 62; j >= 0; j--) if(dp[v][0][j]) add(tt, dp[v][0][j]);
            if(u != v) for(int j = 62; j >= 0; j--) if(dp[fa[u][0]][0][j]) add(tt, dp[fa[u][0]][0][j]);
            for(int i = 62; i >= 0; i--) if((ans^tt[i]) > ans) ans = ans^tt[i];
            printf("%lld
    ", ans);
        }
    }
    View Code
  • 相关阅读:
    Nuget:aliyun-openapi-sdk
    iptables简述
    openOffice安装
    bash:command not found
    linux nc命令
    linux命令帮助
    linux用户管理
    LDAP 后缀操作
    LDAP缓存命令
    LDAP索引及缓存优化
  • 原文地址:https://www.cnblogs.com/Pneuis/p/9090350.html
Copyright © 2011-2022 走看看