loj #2013. 「SCOI2016」幸運數字

#2013. 「SCOI2016」幸運數字

題目描述

A 國共有 n nn 座城市,這些城市由 n−1 n - 1n1 條道路相連,使得任意兩座城市能夠互達,且路徑惟一。每座城市都有一個幸運數字,以記念碑的形式矗立在這座城市的正中心,做爲城市的象徵。一些旅行者但願遊覽 A 國。旅行者計劃乘飛機降落在 x xx 號城市,沿着 x xx 號城市到 y yy 號城市之間那條惟一的路徑遊覽,最終從 y yy 城市起飛離開 A 國。html

在通過每一座城市時,遊覽者就會有機會與這座城市的幸運數字拍照,從而將這份幸運保存到本身身上。然而,幸運是不能簡單疊加的,這一點遊覽者也十分清楚。他們迷信着幸運數字是以異或的方式保留在本身身上的。例如,遊覽者拍了 3 33 張照片,幸運值分別是 5 5五、7 7七、11 1111,那麼最終保留在本身身上的幸運值就是 9 99(5xor7xor11)。node

有些聰明的遊覽者發現,只要選擇性地進行拍照,便能得到更大的幸運值。例如在上述三個幸運值中,只選擇 5 55 和 11 1111 ,能夠保留的幸運值爲 14 1414 。如今,一些遊覽者找到了聰明的你,但願你幫他們計算出在他們的行程安排中能夠保留的最大幸運值是多少。ios

輸入格式

第一行包含兩個正整數 n nn、q qq,分別表示城市的數量和旅行者數量。
第二行包含 n nn 個非負整數,其中第 i ii 個整數 Gi G_iGi​​ 表示 i ii 號城市的幸運值。隨後 n−1 n - 1n1 行,每行包含兩個正整數 x xx、y yy,表示 x xx 號城市和 y yy 號城市之間有一條道路相連。
隨後 q qq 行,每行包含兩個正整數 x xx、y yy,表示這名旅行者的旅行計劃是從 x xx 號城市到 y yy 號城市。
ui

輸出格式

輸出須要包含 q qq 行,每行包含 1 11 個非負整數,表示這名旅行者能夠保留的最大幸運值。atom

樣例

樣例輸入

4 2
11 5 7 9
1 2
1 3
1 4
2 3
1 4

樣例輸出

14
11

數據範圍與提示

N≤20000,Q≤200000,Gi≤260 N \leq 20000, Q \leq 200000, G_i \leq 2 ^ {60}N20000,Q200000,Gi​​260​​spa

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#define maxn 20010
using namespace std;
int n,q,num,head[maxn],fa[maxn][15],dep[maxn];
long long st[maxn][15][62],t[62],lb[62],ans;
struct node{int to,pre;}e[maxn*2];
long long qread(){
    long long i=0,j=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')j=-1;ch=getchar();}
    while(ch<='9'&&ch>='0'){i=i*10+ch-'0';ch=getchar();}
    return i*j;
}
void Insert(int from,int to){
    e[++num].to=to;
    e[num].pre=head[from];
    head[from]=num;
}
void dfs(int x){
    for(int i=1;dep[x]-(1<<i)>0;i++)
        fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=head[x];i;i=e[i].pre){
        int to=e[i].to;
        if(to==fa[x][0])continue;
        dep[to]=dep[x]+1;fa[to][0]=x;
        dfs(to);
    }
}
void merge(long long a[],long long c[]){
    for(int i=0;i<=60;i++)t[i]=a[i];
    for(int i=0;i<=60;i++)
        for(int j=60;j>=0;j--){
            if(!t[i])break;
            if(t[i]>>j&1){
                if(!c[j]){c[j]=t[i];break;}
                else t[i]^=c[j];
            }
        }
}
int lca(int x,int y){
    if(dep[x]<dep[y])swap(x,y);
    for(int i=14;i>=0;i--)
        if(fa[x][i]&&dep[fa[x][i]]>dep[y])
        x=fa[x][i];
    if(dep[x]>dep[y])x=fa[x][0];
    if(x==y)return x;
    for(int i=14;i>=0;i--)
        if(fa[x][i]&&fa[y][i]&&fa[x][i]!=fa[y][i])
        x=fa[x][i],y=fa[y][i];
    return fa[x][0];
}
int cal(int x,int goal){
    if(dep[x]==goal)return x;
    for(int i=14;i>=0;i--)
        if(fa[x][i]&&dep[fa[x][i]]>goal)
        x=fa[x][i];
    return fa[x][0];
}
int main(){
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        long long x=qread();
        for(int j=60;j>=0;j--)
            if(x>>j&1){
                st[i][0][j]=x;
                break;
            }
    }
    for(int i=1;i<n;i++){
        int x=qread(),y=qread();
        Insert(x,y);Insert(y,x);
    }
    dep[1]=1;
    dfs(1);
    for(int i=1;1<<i<=n;i++)
        for(int j=1;j<=n;j++)
        if(dep[j]-(1<<i)>=0)
        merge(st[j][i-1],st[j][i]),
        merge(st[cal(j,dep[j]-(1<<i-1))][i-1],st[j][i]);
    int x,y,z,p1,p2;
    while(q--){
        memset(lb,0,sizeof(lb));
        scanf("%d%d",&x,&y);
        ans=0;z=lca(x,y);
        p1=log2(dep[x]-dep[z]+1);
        merge(st[x][p1],lb);
        merge(st[cal(x,dep[z]+(1<<p1)-1)][p1],lb);
        p2=log2(dep[y]-dep[z]+1);
        merge(st[y][p2],lb);
        merge(st[cal(y,dep[z]+(1<<p2)-1)][p2],lb);
        for(int i=60;i>=0;i--)
            if(!(ans>>i&1))ans^=lb[i];
        printf("%lld\n",ans);
    }
    return 0;
}
相關文章
相關標籤/搜索