zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    SharePoint 2013 中的SQL Server 安全
    SharePoint 2013 的HTML5特性之响应式布局
    SharePoint 2013 一些小技巧
    SharePoint 2013 排错之"Code blocks are not allowed in this file"
    SharePoint 2013 创建搜索中心及搜索设置
    SharePoint 2013 使用PowerShell创建State Service
    SharePoint 2013 内容部署功能简介
    SharePoint 使用PowerShell恢复误删的网站集
    SharePoint 自定义WebPart之间的连接
    linux之misc及使用misc创建字符设备
  • 原文地址:https://www.cnblogs.com/asdfsag/p/10011742.html
Copyright © 2011-2022 走看看