CF840E 题解

发布时间 2023-05-17 06:55:44作者: gtm1514

怪异题。

阈值分治。权值不超过 \(2^{16}=65536\),于是把前后八位砍开。把每个点和上边 \(256\) 个点分成一块,那么每块内的 \(dis\) 的前八位是相同的,因此可以分开考虑。

前边 \(8\) 位设一个 \(f_{x,i}\) 表示跳了 \(i\) 块跳到 \(x\),这一块的前八位最大值。这个暴力把这一块的所有点插进 01Trie 然后枚举一遍 \(i\) 暴力判就可以。

后边 \(8\) 位设一个 \(g_{i}\) 为前八位权值为 \(i\) 时异或 \(dis\) 的后八位最大值,这个也暴力往上扫 \(256\) 个点记录就行。然后查的时候保证前八位最大,可以通过前八位得到后八位的值。

代码很好写。

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <vector>
using namespace std;
int n,m;
struct node{
    int v,next;
}edge[100010];
int t,head[50010],val[50010];
void add(int u,int v){
    edge[++t].v=v;edge[t].next=head[u];head[u]=t;
}
struct Trie{
    int cnt,trie[2100][2];
    void clear(){
        for(int i=0;i<=cnt;i++)trie[i][0]=trie[i][1]=0;cnt=0;
    }
    void ins(int x){
        int p=0;
        for(int i=7;i>=0;i--){
            int w=(x>>i)&1;
            if(!trie[p][w])trie[p][w]=++cnt;
            p=trie[p][w];
        }
    }
    int query(int x){
        int p=0,ans=0;
        for(int i=7;i>=0;i--){
            int w=(x>>i)&1;ans<<=1;
            if(trie[p][w^1])ans|=1,p=trie[p][w^1];
            else p=trie[p][w];
        }
        return ans;
    }
}T;
int fa[50010],f[50010][256],g[256],pre[50010],dep[50010];
void dfs(int x,int faa){
    fa[x]=faa;dep[x]=dep[faa]+1;
    if(dep[x]>=256){
        T.clear();int u=x;
        memset(g,0,sizeof(g));
        for(int dis=0;dis<(1<<8);u=fa[u],dis++){
            g[val[u]>>8]=max(g[val[u]>>8],dis^val[u]&255);
            T.ins(val[u]>>8);
        }
        pre[x]=u;
        for(int i=0;i<(1<<8);i++){
            int ans=T.query(i);
            f[x][i]=ans<<8|g[ans^i];
        }
    }
    for(int i=head[x];i;i=edge[i].next){
        if(edge[i].v!=faa)dfs(edge[i].v,x);
    }
}
int query(int x,int y){
    int dis=0,ans=0;
    while(dep[y]-dep[x]>=256)ans=max(ans,f[y][dis]),y=pre[y],dis++;
    dis<<=8;
    while(y!=fa[x])ans=max(ans,val[y]^dis),dis++,y=fa[y];
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&val[i]);
    for(int i=1;i<n;i++){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    dfs(1,0);
    while(m--){
        int u,v;scanf("%d%d",&u,&v);
        printf("%d\n",query(u,v));
    }
    return 0;
}