zoukankan      html  css  js  c++  java
  • HDU 6191 2017ACM/ICPC广西邀请赛 J Query on A Tree 可持久化01字典树+dfs序

    题意

    给一颗(n)个节点的带点权的树,以(1)为根节点,(q)次询问,每次询问给出2个数(u),(x),求(u)的子树中的点上的值与(x)异或的值最大为多少

    分析

    先dfs一遍,得到dfs序,就可以将这个问题转化为求区间([l,r])中的值与(x)异或值最大的经典问题,

    就按dfs序建可持久化01字典树,查询的时候查区间([in[u],out[u]])就行了,(in[u])(out[u])存的分别是(u)的子树上的节点在dfs序上的起始位置和结尾位置。

    Code

        #include<bits/stdc++.h>
        #define fi first
        #define se second
        using namespace std;
        typedef long long ll;
        const double PI=acos(-1.0);
        const double eps=1e-6;
        const int inf=1e9;
        const ll mod=1e9+7;
        const int maxn=1e5+10;
        int n,q;
        int v[maxn];
        vector<int>f[maxn];
        int in[maxn],out[maxn];
        int r;
        int a[maxn];
        int root[maxn];
        int son[maxn*40][2],tot;
        int sum[maxn*40];
        void dfs(int u,int fa){
            in[u]=++r;a[r]=u;
            for(int x:f[u]){
                if(x==fa) continue;
                dfs(x,u);
            }
            out[u]=r;
        }
        int insert(int val,int pre){
            int x=++tot,pos=x;
            for(int i=30;i>=0;i--){
                son[x][0]=son[pre][0];
                son[x][1]=son[pre][1];
                int j=((val>>i)&1);
                son[x][j]=++tot;
                x=son[x][j];pre=son[pre][j];
                sum[x]=sum[pre]+1;
            }
            return pos;
        }
        int query(int val,int l,int r){
            int ans=0;
            for(int i=30;i>=0;i--){
                int j=((val>>i)&1);j=!j;
                if(sum[son[r][j]]-sum[son[l][j]]>0){
                    ans|=(1<<i);
                }else{
                    j=!j;
                }
                l=son[l][j];r=son[r][j];
            }
            return ans;
        }
        int main(){
            ios::sync_with_stdio(false);
            while(cin>>n>>q){
                memset(son,0,sizeof(son));
                memset(sum,0,sizeof(sum));
                memset(root,0,sizeof(root));
                memset(a,0,sizeof(a));
                memset(in,0,sizeof(in));
                memset(out,0,sizeof(out));
                r=tot=0;
                for(int i=1;i<=n;i++){
                    cin>>v[i];
                    f[i].clear();
                }
                for(int i=1,x;i<n;i++){
                    cin>>x;
                    f[x].push_back(i+1);
                }
                dfs(1,0);
                for(int i=1;i<=n;i++){
                    root[i]=insert(v[a[i]],root[i-1]);
                }
                while(q--){
                    int u,x;
                    cin>>u>>x;
                    int ans=query(x,root[in[u]-1],root[out[u]]);
                    cout<<ans<<endl;
                }
            }
            return 0;
        }
    
  • 相关阅读:
    使用浏览器的 Local Storage 真的安全吗?
    传统到敏捷的转型中,谁更适合做Scrum Master?
    HBM2E Flashbolt--提升人工智能的算力
    C语言 for 循环
    C语言自加自减运算符(++i / i++)
    C语言逗号表达式
    C语言逻辑运算符
    C语言三目运算符
    C语言条件判断 if / else
    C语言 printf 函数
  • 原文地址:https://www.cnblogs.com/xyq0220/p/10759474.html
Copyright © 2011-2022 走看看