• 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
  • 相关阅读:
    vps安装wordpress遇到的问题(lnmp)
    RING0,RING1,RING2,RING3
    CentOS 下配置CUPS
    怎样解决VS2013模块对于SAFESEH 映像是不安全的
    【转】VC6.0打开或者添加工程文件崩溃的解决方法
    QWidget QMainWindow QDialog 三个基类的区别
    在C语言中,double、long、unsigned、int、char类型数据所占字节数
    拷贝构造函数
    “浅拷贝”与“深拷贝”
    常用软件列表
  • 原文地址:https://www.cnblogs.com/Pneuis/p/9090350.html
Copyright © 2020-2023  润新知