bzoj4568 [Scoi2016]幸运数字 倍增+线性基

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/82430751

Description


A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个
幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。一些旅行者希望游览 A 国。旅行者计划
乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国。
在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。然而,幸
运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。例如,
游览者拍了 3 张照片,幸运值分别是 5,7,11,那么最终保留在自己身上的幸运值就是 9(5 xor 7 xor 11)。
有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择 5
和 11 ,可以保留的幸运值为 14 。现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中
可以保留的最大幸运值是多少。

N<=20000,Q<=200000,Gi<=2^60

Solution


异或最大值,考虑用线性基做。
直接倍增,rec[x][i]表示x向上2^i个组成的线性基,倍增的时候合并线性基就可以了
合并线性基就是把一个线性基中的元素插入另一个里面

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)
#define fill(x,t) memset(x,t,sizeof(x))

typedef long long LL;
const int N=20005;

struct edge {int y,next;} e[N*2];
struct Bin {
    LL r[61];

    bool ins(LL x) {
        drp(i,60,0) if (x&(1LL<<i)) {
            if (r[i]) x^=r[i];
            else {r[i]=x; return true;}
        }
        return x==0;
    }

    LL get_max() {
        LL ret=0;
        drp(i,60,0) if ((ret^r[i])>ret) {
            ret^=r[i];
        }
        return ret;
    }

    void merge(Bin b) {
        rep(i,0,60) if (b.r[i]) {
            ins(b.r[i]);
        }
    }

    void init() {
        fill(r,0);
    }
} rec[N][15];

int dep[N],fa[N][15];
int ls[N],edCnt;

LL v[N];

void add_edge(int x,int y) {
    e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
    e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}

void dfs(int now) {
    rep(i,1,14) {
        fa[now][i]=fa[fa[now][i-1]][i-1];
        rec[now][i]=rec[now][i-1];
        rec[now][i].merge(rec[fa[now][i-1]][i-1]);
    }
    for (int i=ls[now];i;i=e[i].next) {
        if (e[i].y==fa[now][0]) continue;
        fa[e[i].y][0]=now; dep[e[i].y]=dep[now]+1;
        rec[e[i].y][0].ins(v[now]);
        dfs(e[i].y);
    }
}

int get_lca(int x,int y) {
    if (dep[x]<dep[y]) std:: swap(x,y);
    drp(i,14,0) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    if (x==y) return x;
    drp(i,14,0) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}

int main(void) {
    int n,q; scanf("%d%d",&n,&q); Bin S;
    rep(i,1,n) scanf("%lld",&v[i]);
    rep(i,2,n) {
        int x,y; scanf("%d%d",&x,&y);
        add_edge(x,y);
    }
    for (dfs(dep[1]=1);q--;) {
        int x,y; scanf("%d%d",&x,&y);
        int lca=get_lca(x,y);
        S.init(); S.ins(v[x]); S.ins(v[y]);
        drp(i,14,0) if (dep[fa[x][i]]>=dep[lca]) {
            S.merge(rec[x][i]); x=fa[x][i];
        }
        drp(i,14,0) if (dep[fa[y][i]]>=dep[lca]) {
            S.merge(rec[y][i]); y=fa[y][i];
        }
        printf("%lld\n", S.get_max());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/82430751