HDU4757:Tree——题解

http://acm.hdu.edu.cn/showproblem.php?pid=4757

给一棵有点值的树,每次询问u~v的最短路当中的一个点的点权异或z最大值。

前置技能:HDU4825

前置技能:BZOJ3261(可持久化trie)

默认你会如何建可持久化trie跑贪心了。

emmmm既然你已经懂了那还说啥,u~v的链可以剖成u~lca和v~lca,即每次询问这两个链和z异或的最大值即可。

PS:注意询问的时候区间左端点-1,即询问的是rt[fa(lca)]~rt[u/v]。

#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=1e5+5;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct trie{
    int son[2],sum;
}tr[40*N];
struct node{
    int to,nxt;
}e[N*2];
int tot,a[N],rt[N],pool,cnt,head[N];
int dep[N],anc[N][20];
inline void add(int u,int v){
    e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
inline void addtwo(int u,int v){
    add(u,v);add(v,u);
}
void insert(int y,int &x,int k,int now){
    tr[x=++pool]=tr[y];
    tr[x].sum++;
    if(now<0)return;
    bool p=k&(1<<now);
    insert(tr[y].son[p],tr[x].son[p],k,now-1);
    return;
}
int query(int nl,int nr,int k,int now){
    if(now<0)return 0;
    bool p=k&(1<<now);
    int delta=tr[tr[nr].son[p^1]].sum-tr[tr[nl].son[p^1]].sum;
    if(delta>0)return (1<<now)+query(tr[nl].son[p^1],tr[nr].son[p^1],k,now-1);
    else return query(tr[nl].son[p],tr[nr].son[p],k,now-1);
}
void dfs(int u,int f){
    anc[u][0]=f;
    for(int k=1;k<=18;k++)
    anc[u][k]=anc[anc[u][k-1]][k-1];
    dep[u]=dep[f]+1;
    insert(rt[f],rt[u],a[u],15);
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(v!=f)dfs(v,u);
    }
    return;
}
inline int LCA(int i,int j){
    if(dep[i]<dep[j])swap(i,j);
    for(int k=18;k>=0;k--){
        if(dep[anc[i][k]]>=dep[j])i=anc[i][k];
    }
    if(i==j)return i;
    for(int k=18;k>=0;k--){
        if(anc[i][k]!=anc[j][k])i=anc[i][k],j=anc[j][k];
    }
    return anc[i][0];
}
inline void init(){
    memset(tr,0,sizeof(tr));
    memset(rt,0,sizeof(rt));
    memset(head,0,sizeof(head));
    tot=1;cnt=pool=0;
}
int main(){
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
    init();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<n;i++)addtwo(read(),read());
    dfs(1,0);
    for(int i=1;i<=m;i++){
        int u=read(),v=read(),x=read(),lca=LCA(u,v),fa=anc[lca][0];
        printf("%d\n",max(query(rt[fa],rt[u],x,15),
                  query(rt[fa],rt[v],x,15)));
    }
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

posted @ 2018-03-08 15:41  luyouqi233  阅读(280)  评论(0编辑  收藏  举报