• HDU


    题目链接

    题意:有一棵树,树根为1,树上的每个结点都有一个数字x。给出Q组询问,每组询问有两个值u,x,代表询问以结点u为根的子树中的某一个数与x的最大异或值。

    解法一:dfs序+可持久化字典树。看到子树询问,首先要想到dfs序啦。可以对所有结点按dfs序依次建立可持久化的字典树,字典树上的每个结点除了要保存它的后继结点以外,还要保存这个结点出现的次数num。询问结点u时,对[bg[u],ed[u]]上的字典树的num做差,字典树上剩下的num>0的结点即为可行状态,然后按普通的字典树的查询方法查询就是了。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    const int M=30;
    int n,Q,head[N],nxt[N],to[N],val[N],nEdge;
    int rt[N],num[N*32],go[N*32][2],nnode;
    int bg[N],ed[N],tot;
    void AddEdge(int u,int v) {
        nxt[nEdge]=head[u],to[nEdge]=v,head[u]=nEdge++;
    }
    
    int update(int v,int x,int bit) {
        int u=++nnode;
        num[u]=num[v]+1;
        if(bit<0)return u;
        int t=(x>>bit)&1;
        go[u][t]=update(go[v][t],x,bit-1);
        go[u][t^1]=go[v][t^1];
        return u;
    }
    
    void dfs(int u) {
        bg[u]=++tot;
        rt[tot]=update(rt[tot-1],val[u],M);
        for(int e=head[u]; ~e; e=nxt[e]) {
            int v=to[e];
            dfs(v);
        }
        ed[u]=tot;
    }
    
    int query(int u,int v,int x,int bit,int now) {
        if(bit<0)return now;
        int t=(x>>bit)&1;
        if(go[u][t^1]-go[v][t^1]>0)
            return query(go[u][t^1],go[v][t^1],x,bit-1,now|(1<<bit));
        else return query(go[u][t],go[v][t],x,bit-1,now);
    }
    
    int main() {
        while(scanf("%d%d",&n,&Q)==2) {
            memset(head,-1,sizeof head);
            nEdge=nnode=tot=0;
            for(int i=1; i<=n; ++i)scanf("%d",&val[i]);
            for(int i=2; i<=n; ++i) {
                int u;
                scanf("%d",&u);
                AddEdge(u,i);
            }
            rt[0]=go[0][0]=go[0][1]=num[0]=0;
            dfs(1);
            while(Q--) {
                int u,x;
                scanf("%d%d",&u,&x);
                printf("%d
    ",query(rt[ed[u]],rt[bg[u]-1],x,M,0));
            }
        }
        return 0;
    }

    解法二:离线+字典树合并。可以自底而上来回答询问,每回答完一个结点下的所有子节点的询问,就将这个结点的字典树与它所有子节点的字典树合并。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    const int M=30;
    int n,Q,head[N],nxt[N],to[N],val[N],nEdge;
    int rt[N],go[N*32][2],nnode,ans[N];
    struct QUERY {
        int x,i;
    };
    vector<QUERY> qr[N];
    void AddEdge(int u,int v) {
        nxt[nEdge]=head[u],to[nEdge]=v,head[u]=nEdge++;
    }
    
    int build(int x,int bit) {
        int u=++nnode;
        if(bit<0)return u;
        int t=(x>>bit)&1;
        go[u][t]=build(x,bit-1);
        go[u][t^1]=0;
        return u;
    }
    
    int Merge(int u,int v,int bit) {
        if(!u)return v;
        if(!v)return u;
        if(bit<0)return u;
        go[u][0]=Merge(go[u][0],go[v][0],bit-1);
        go[u][1]=Merge(go[u][1],go[v][1],bit-1);
        return u;
    }
    
    int query(int u,int x,int bit,int now) {
        if(bit<0)return now;
        int t=(x>>bit)&1;
        if(go[u][t^1])
            return query(go[u][t^1],x,bit-1,now|(1<<bit));
        else return query(go[u][t],x,bit-1,now);
    }
    
    void dfs(int u) {
        for(int e=head[u]; ~e; e=nxt[e]) {
            int v=to[e];
            dfs(v);
        }
        for(int e=head[u]; ~e; e=nxt[e]) {
            int v=to[e];
            rt[u]=Merge(rt[u],rt[v],M);
        }
        for(int i=0; i<qr[u].size(); ++i) {
            ans[qr[u][i].i]=query(rt[u],qr[u][i].x,M,0);
        }
    }
    
    int main() {
        while(scanf("%d%d",&n,&Q)==2) {
            memset(head,-1,sizeof head);
            nEdge=nnode=0;
            for(int i=0; i<=n; ++i)qr[i].clear();
            for(int i=1; i<=n; ++i)scanf("%d",&val[i]);
            for(int i=2; i<=n; ++i) {
                int u;
                scanf("%d",&u);
                AddEdge(u,i);
            }
            for(int i=1; i<=n; ++i)rt[i]=build(val[i],M);
            for(int i=0; i<Q; ++i) {
                int u,x;
                scanf("%d%d",&u,&x);
                qr[u].push_back({x,i});
            }
            dfs(1);
            for(int i=0; i<Q; ++i)printf("%d
    ",ans[i]);
        }
        return 0;
    }

     还有一种解法是“可持久化字典树合并”,即父结点继承所有子结点的字典树,继承的方式与字典树合并一样,只不过把两棵树的公共部分开新结点就好,也是在线的,但空间消耗较大。

    #define FRER() freopen("i.txt","r",stdin)
    #define FREW() freopen("o.txt","w",stdout)
    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    const int M=30;
    int n,Q,head[N],nxt[N],to[N],val[N],nEdge;
    int rt[N],go[N*64][2],nnode,ans[N];
    void AddEdge(int u,int v) {
        nxt[nEdge]=head[u],to[nEdge]=v,head[u]=nEdge++;
    }
    int build(int x,int bit) {
        int u=++nnode;
        if(bit<0)return u;
        int t=(x>>bit)&1;
        go[u][t]=build(x,bit-1);
        go[u][t^1]=0;
        return u;
    }
    
    int Merge(int u,int v,int bit) {
        if(!u)return v;
        if(!v)return u;
        if(bit<0)return u;
        int w=++nnode;
        go[w][0]=Merge(go[u][0],go[v][0],bit-1);
        go[w][1]=Merge(go[u][1],go[v][1],bit-1);
        return w;
    }
    int query(int u,int x,int bit,int now) {
        if(bit<0)return now;
        int t=(x>>bit)&1;
        if(go[u][t^1])
            return query(go[u][t^1],x,bit-1,now|(1<<bit));
        else return query(go[u][t],x,bit-1,now);
    }
    void dfs(int u) {
        for(int e=head[u]; ~e; e=nxt[e]) {
            int v=to[e];
            dfs(v);
        }
        for(int e=head[u]; ~e; e=nxt[e]) {
            int v=to[e];
            rt[u]=Merge(rt[u],rt[v],M);
        }
    }
    
    int main() {
        while(scanf("%d%d",&n,&Q)==2) {
            memset(head,-1,sizeof head);
            nEdge=nnode=0;
            for(int i=1; i<=n; ++i)scanf("%d",&val[i]);
            for(int i=2; i<=n; ++i) {
                int u;
                scanf("%d",&u);
                AddEdge(u,i);
            }
            for(int i=1; i<=n; ++i)rt[i]=build(val[i],M);
            dfs(1);
            for(int i=0; i<Q; ++i) {
                int u,x;
                scanf("%d%d",&u,&x);
                printf("%d
    ",query(rt[u],x,M,0));
            }
        }
        return 0;
    }
  • 相关阅读:
    tensorflow搭建神经网络基本流程
    为什么Linux 实例执行 df 和 du 查看磁盘时结果不一致
    MySQL高可用架构之MHA
    Postgresql 用户管理
    PXE+Kickstart无人值守安装CentOS 7
    linux shell实用常用命令
    常用压缩命令
    mongodb 备份还原
    mongodb 备份脚本
    mongodb 日志清理
  • 原文地址:https://www.cnblogs.com/asdfsag/p/10011742.html
Copyright © 2020-2023  润新知