zoukankan      html  css  js  c++  java
  • HDU4757 Tree(可持久化Trie)

    写过可持久化线段树,但是从来没写过可持久化的Trie,今天补一补。

    题目就是典型的给你一个数x,和一个数集,问x和里面的某个数xor起来的最大值是多少。

    最原始的是数集是固定的,只需要对数集按照高到低位去建Trie,然后贪心匹配就可以了。

    这里则是对树上路径的操作,其实也是一样的,对每个节点x维护root到x的Trie,然后纪录下往左走往右走的叶子节点个数,设z=lca(x,y),那么到了个某个节点能否往某个儿子走的限制条件是 sz[ch[x][c]]+sz[ch[y][c]]-2*sz[ch[z][c]]>0,这样说明下面是存在c的儿子的,接着往下走即可。当然这样算其实是会漏掉lca的,所以最后还要和lca取最大值。

    区间的询问作为这题的特例同理也是可以处理的。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <cassert>
    #include <vector>
    #include <set>
    using namespace std;
    
    #define maxn 120000
    #define maxnode 2200000
    #define maxlogv 16
    vector<int> G[maxn];
    int n,m;
    int a[maxn];
    
    int f[maxlogv+2][maxn];
    int dep[maxn];
    int ch[maxnode][2];
    int sz[maxnode];
    int tot;
    int root[maxn];
    
    int newnode(){
        memset(ch[tot],0,sizeof(ch[tot]));
        sz[tot]=0;
        return tot++;
    }
    
    // insert val for x with father as y
    void insert(int x,int y,int val)
    {
        x=root[x];y=root[y];
        for(int i=15;i>=0;--i){
            int c=(val>>i)&1;
            if(!ch[x][c]){
                int id=newnode();
                ch[x][c]=id;
                ch[x][!c]=ch[y][!c];
                sz[ch[x][c]]=sz[ch[y][c]];
            }
            x=ch[x][c],y=ch[y][c];
            ++sz[x];
        }
    }
    
    void dfs(int u,int fa)
    {
        f[0][u]=fa;dep[u]=dep[fa]+1;
        root[u]=newnode();
        insert(u,fa,a[u]);
        for(int i=0;i<G[u].size();++i){
            int v=G[u][i];
            if(v==fa) continue;
            dfs(v,u);
        }
    }
    
    int lca(int u,int v)
    {
        if(dep[u]>dep[v]) swap(u,v);
        for(int k=0;k<maxlogv;++k){
            if( (dep[v]-dep[u])>>k&1){
                v=f[k][v];
            }
        }
        if(u==v) return u;
        for(int k=maxlogv-1;k>=0;--k){
            if(f[k][u]!=f[k][v]){
                u=f[k][u];
                v=f[k][v];
            }
        }
        return f[0][u];
    }
    
    int query(int x,int y,int val)
    {
        int z=lca(x,y);int res=a[z]^val;
        x=root[x],y=root[y],z=root[z];
        int ret=0;
        for(int i=15;i>=0;--i){
            int c=(val>>i)&1;
            if(sz[ch[x][!c]]+sz[ch[y][!c]]-2*sz[ch[z][!c]]>0){
                ret+=1<<i;
                c=!c;
            }
            x=ch[x][c];
            y=ch[y][c];
            z=ch[z][c];
        }
        return max(ret,res);
    }
    
    
    int main()
    {
        while(cin>>n>>m){
            for(int i=1;i<=n;++i){
                scanf("%d",a+i);
                G[i].clear();
            }
            int ui,vi;
            for(int i=0;i<n-1;++i){
                scanf("%d%d",&ui,&vi);
                G[ui].push_back(vi);
                G[vi].push_back(ui);
            }
            memset(root,0,sizeof(root));
            tot=1;
            memset(f,0,sizeof(f));
            memset(sz,0,sizeof(sz));
            dep[0]=0;
            dfs(1,0);
            for(int k=0;k+1<maxlogv;++k){
                for(int v=1;v<=n;++v){
                    if(f[k][v]==0) f[k+1][v]=0;
                    else f[k+1][v]=f[k][f[k][v]];
                }
            }
            int xi,yi,zi;
            for(int i=0;i<m;++i){
                scanf("%d%d%d",&xi,&yi,&zi);
                printf("%d
    ",query(xi,yi,zi));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    Verilog --序列检测器(采用移位寄存器实现)
    SV -- Randomization 随机化
    SV -- Interprocess Communication (IPC 线程间通信)
    SV -- Class 类
    Verilog -- 序列模三(整除3)检测器
    VSCode+C++环境搭建
    在次线性时间内计算线性递归数列
    Codefest19受虐记
    ABC135记录
    Paint.NET软件分享
  • 原文地址:https://www.cnblogs.com/chanme/p/4074858.html
Copyright © 2011-2022 走看看