HDU 4757 Tree(可持久化01trie+LCA)

传送门

给定无根树,带点权,m次询问,每次询问给出x,y,z,问x到y的简单路径上的点,与z进行异或运算,结果最大是多少。

求与给定常数的异或最大值,妥妥的01字典树。
对于树上两点路径问题,可以考虑引入LCA。
我们可以把x,y的简单路径拆分成两条链
x->lca(x,y);
y->lca(x,y);

分别在两条链上找答案然后取最大值。

如何找答案呢,先假设根节点是1,我们可以对每个节点建一个01trie,表示其到1的路径上的点建成的01trie,由于该节点与其父节点相比只多了一条链,所以可以建可持久化01trie。

查询:
root[x]-root[fa[lca]]root[y]]-root[fa[lca]]中查询,取max

关于数组初始化的细节:
涉及多组数据的时候,由于我们root[]从0版本开始,root[0]的左右孩子都是已经更新了的,所以下一个版本root[1]也是如此,同理推广到root[n]。
所以存字典树的数组是不需要初始化的。

#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
const int maxn = 1e5 + 10;
const ll mod = 998244353;
const ll inf = (ll)4e17+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){
    
    if(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
inline ll read()
{
    
    
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){
    
    if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){
    
    x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
//给定带点权的数 q次询问 每次问x y节点路径上的点 与z异或的最大值
//每个节点建trie树 表示1到该节点路径上的点建成的trie树 
//u->lca lca->v 两条链  u-fa[lca] v-fa[lca]
int cnt[maxn*40],ch[maxn*40][2],tot,root[maxn];
int a[maxn];
int n,m;
int fa[maxn];
vector<int> g[maxn];
int dep[maxn],sz[maxn],son[maxn],top[maxn];
void init()
{
    
    
    for(int i=1;i<=n;i++) 
    {
    
    
        g[i].clear();
        son[i]=0;
    }
    tot=0;
}
inline void upd(int rt,int last,int d,int v)
{
    
    
    if(d < 0) return ;
    int i=(v>>d)&1;
    ch[rt][!i]=ch[last][!i];
    ch[rt][i]=++tot;
    cnt[ch[rt][i]]=cnt[ch[last][i]]+1;
    upd(ch[rt][i],ch[last][i],d-1,v);
}
inline int qry(int rt1,int rt2,int d,int v)
{
    
    
    if(d < 0) return 0;
    int i=(v>>d)&1;
    if(cnt[ch[rt1][!i]] > cnt[ch[rt2][!i]]) 
        return (1<<d) + qry(ch[rt1][!i] , ch[rt2][!i] , d-1 , v);
    else return qry(ch[rt1][i] , ch[rt2][i] , d-1 , v);
}
void dfs(int rt,int f)
{
    
    
    root[rt]=++tot;
    upd(root[rt],root[f],20,a[rt]);//在父节点基础上建树
    fa[rt]=f;
    sz[rt]=1;
    dep[rt]=dep[f]+1;
    for(int i:g[rt]) 
    {
    
    
        if(i==f) continue;
            dfs(i,rt);
        sz[rt]+=sz[i];
        if(sz[i] > sz[son[rt]]) son[rt]=i;
    }
}
void chain(int rt,int t) 
{
    
    
    top[rt]=t;
    if(son[rt]) chain(son[rt],t);
    for(int i:g[rt]) 
    {
    
    
        if(i==fa[rt] || i==son[rt]) continue;
        chain(i,i);
    }
}
inline int get_lca(int x,int y) 
{
    
    
    int fx=top[x],fy=top[y];
    while(fx != fy) 
    {
    
    
        if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
        x=fa[fx];
        fx=top[x];
    }
    //x y在同一条链
    if(dep[x] < dep[y]) return x;
    else return y;
}
int main()
{
    
    
    while(~scanf("%d %d",&n,&m))
    {
    
    
        init();
        for(int i=1;i<=n;i++) scanf("%d",a+i);
        for(int i=1,u,v;i<n;i++)
        {
    
       
            scanf("%d %d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
        root[0]=++tot;
        upd(root[0],0,20,0);
        dfs(1,0);
        chain(1,1);
        int u,v,k;
        while(m--) 
        {
    
    
            scanf("%d %d %d",&u,&v,&k);
            int lca=get_lca(u,v);
            //u->lca lca->v
            printf("%d\n",max(qry(root[u],root[fa[lca]],20,k) , 
                                qry(root[v],root[fa[lca]],20,k) ));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46030630/article/details/120943507
今日推荐