zoukankan      html  css  js  c++  java
  • HDU 4757 Tree(可持久化Trie+Tarjan离线LCA)

    Tree

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Others)
    Total Submission(s): 1643    Accepted Submission(s): 461

    Problem Description
      Zero and One are good friends who always have fun with each other. This time, they decide to do something on a tree which is a kind of graph that there is only one path from node to node. First, Zero will give One an tree and every node in this tree has a value. Then, Zero will ask One a series of queries. Each query contains three parameters: x, y, z which mean that he want to know the maximum value produced by z xor each value on the path from node x to node y (include node x, node y). Unfortunately, One has no idea in this question. So he need you to solve it.
     
    Input
      There are several test cases and the cases end with EOF. For each case:

      The first line contains two integers n(1<=n<=10^5) and m(1<=m<=10^5), which are the amount of tree’s nodes and queries, respectively.

      The second line contains n integers a[1..n] and a[i](0<=a[i]<2^{16}) is the value on the ith node.

      The next n–1 lines contains two integers u v, which means there is an connection between u and v.

      The next m lines contains three integers x y z, which are the parameters of Zero’s query.
     
    Output
      For each query, output the answer.
     
    Sample Input
    3 2
    1 2 2
    1 2
    2 3
     
    1 3 1
    2 3 2
     
    Sample Output
    3
    0
     

    题目链接:HDU 4757

    一道跟COT很像的题,但是用的是可持久化的Trie,做法跟COT基本相同,但是过程中由于N少设了10倍,无限TLE……各种纠结问题出在Tarjan?并查集?插入查询函数?因此过程中还找了题解但发现并没有什么区别,但有另外一种非递归形式的插入查询写法,值得借鉴。另外处理节点LCA的问题上公式还是那条$cnt_{U,V}=cnt_{U}+cnt_{V}-cnt_{LCA}-cnt_{father[LCA]}$

    单纯地减掉两倍可能会出错,不知道网上的例程是什么情况。通过最近几道题了解了可持久化Trie的空间复杂度似乎跟Trie是一样的,都是Total*maxlen(如果撇开相对来说只有一丢丢的root数组不说的话)

    递归更新查询的代码:

    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <sstream>
    #include <cstring>
    #include <bitset>
    #include <string>
    #include <deque>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <set>
    #include <map>
    using namespace std;
    #define INF 0x3f3f3f3f
    #define CLR(arr,val) memset(arr,val,sizeof(arr))
    #define LC(x) (x<<1)
    #define RC(x) ((x<<1)+1)
    #define MID(x,y) ((x+y)>>1)
    typedef pair<int,int> pii;
    typedef long long LL;
    const double PI=acos(-1.0);
    const int N=1e5+7;
    struct Trie
    {
        int nxt[2];
        int cnt;
    };
    struct edge
    {
        int to,nxt;
    };
    struct Query
    {
        int to,nxt,id,lca;
    };
    struct ask
    {
        int u,v,lca,val;
    };
    ask q[N];
    Trie L[N*18];int cnt;
    Query Q[N<<1];int qtot,qhead[N];
    edge E[N<<1];int tot,head[N];
    int ances[N],pre[N],Father[N];
    bitset<N>vis;
    int arr[N],root[N];
    
    void init()
    {
        CLR(L,0);cnt=0;
        CLR(head,-1);tot=0;
        CLR(qhead,-1);qtot=0;
        CLR(ances,0);
        for (int i=0; i<N; ++i)
            pre[i]=i;
        CLR(Father,0);
        vis.reset();
        CLR(root,0);
    }
    inline void add(const int &s,const int &t)
    {
        E[tot].to=t;
        E[tot].nxt=head[s];
        head[s]=tot++;
    }
    inline void addQ(const int &s,const int &t,const int &id)
    {
        Q[qtot].to=t;
        Q[qtot].id=id;
        Q[qtot].lca=1;
        Q[qtot].nxt=qhead[s];
        qhead[s]=qtot++;
    }
    
    void update(int &cur,const int &ori,const int &step,const int &n)
    {
        cur=++cnt;
        L[cur]=L[ori];
        ++L[cur].cnt;
        if(step<0)
            return;
        int t=(n>>step)&1;
        update(L[cur].nxt[t],L[ori].nxt[t],step-1,n);
    }
    int Find(const int &n)
    {
        return n==pre[n]?n:pre[n]=Find(pre[n]);
    }
    void Tarjan(const int &u,const int &Fa)
    {
        vis[u]=1;
        ances[u]=u;
        Father[u]=Fa;
        update(root[u],root[Fa],16,arr[u]);
        for (int i=head[u]; ~i; i=E[i].nxt)
        {
            int v=E[i].to;
            if(!vis[v])
            {
                Tarjan(v,u);
                pre[v]=u;
                ances[Find(u)]=u;
            }
        }
        for (int i=qhead[u]; ~i; i=Q[i].nxt)
        {
            int v=Q[i].to;
            if(vis[v])
                q[Q[i].id].lca=ances[Find(v)];
        }
    }
    int query(const int &U,const int &V,const int &LCA,const int &F_LCA,const int &step,const int &n)
    {
        if(step<0)
            return 0;
        int t=(n>>step)&1;
        int c=L[L[U].nxt[t^1]].cnt+L[L[V].nxt[t^1]].cnt-L[L[LCA].nxt[t^1]].cnt-L[L[F_LCA].nxt[t^1]].cnt;
        if(c>0)
            return (1<<step)+query(L[U].nxt[t^1],L[V].nxt[t^1],L[LCA].nxt[t^1],L[F_LCA].nxt[t^1],step-1,n);
        else
            return query(L[U].nxt[t],L[V].nxt[t],L[LCA].nxt[t],L[F_LCA].nxt[t],step-1,n);
    }
    int main(void)
    {
        int n,m,a,b,i;
        while (~scanf("%d%d",&n,&m))
        {
            init();
            for (i=1; i<=n; ++i)
                scanf("%d",&arr[i]);
            for (i=0; i<n-1; ++i)
            {
                scanf("%d%d",&a,&b);
                add(a, b);
                add(b, a);
            }
            for (i=0; i<m; ++i)
            {
                scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].val);
                addQ(q[i].u, q[i].v, i);
                addQ(q[i].v, q[i].u, i);
            }
            Tarjan(1,0);
            for (i=0; i<m; ++i)
                printf("%d
    ",query(root[q[i].u],root[q[i].v],root[q[i].lca],root[Father[q[i].lca]],16,q[i].val));
        }
        return 0;
    }
    

    网上例程的非递归写法:

    int update(int ori,int n)
    {
        bitset<17> s=n;
        int cur=++cnt;
        int ret=cur;
        L[cur]=L[ori];
        for (int i=16; i>=0; --i)
        {
            int v=s[i];
            L[++cnt]=L[L[cur].nxt[v]];
            ++L[cnt].cnt;
            L[cur].nxt[v]=cnt;
            cur=cnt;
        }
        return ret;
    }
    void Tarjan(const int &u,const int &Fa)
    {
        /*vis[u]=1;
        ances[u]=u;
        Father[u]=Fa;*/
        root[u]=update(root[Fa],arr[u]);
        /*for (int i=head[u]; ~i; i=E[i].nxt)
        {
            int v=E[i].to;
            if(!vis[v])
            {
                Tarjan(v,u);
                pre[v]=u;
                ances[Find(u)]=u;
            }
        }
        for (int i=qhead[u]; ~i; i=Q[i].nxt)
        {
            int v=Q[i].to;
            if(vis[v])
                q[Q[i].id].lca=ances[Find(v)];
        }*/
    }
    int query(int u,int v,int lca,int flca,int n)
    {
        int r=0;
        bitset<17> s=n;
        for (int i=16; i>=0; --i)
        {
            int indx=s[i];
            int c=L[L[u].nxt[indx^1]].cnt+L[L[v].nxt[indx^1]].cnt-L[L[lca].nxt[indx^1]].cnt-L[L[flca].nxt[indx^1]].cnt;
            if(c>0)
            {
                r+=1<<i;
                u=L[u].nxt[indx^1];
                v=L[v].nxt[indx^1];
                lca=L[lca].nxt[indx^1];
                flca=L[flca].nxt[indx^1];
            }
            else
            {
                u=L[u].nxt[indx];
                v=L[v].nxt[indx];
                lca=L[lca].nxt[indx];
                flca=L[flca].nxt[indx];
            }
        }
        return r;
    }
  • 相关阅读:
    CXF JaxWsDynamicClientFactory 错误:编码GBK的不可映射字符
    关于springboot配置DataSource
    Spring Boot2.0加载多个数据源
    Kettle配置发送邮件
    推荐几个不错的VUE UI框架
    vue基础语法一
    Maven在Eclipse下构建多模块项目过程
    利用eclipse把jar包安装到本地仓库
    设计模式之策略模式
    设计模式之观察者模式
  • 原文地址:https://www.cnblogs.com/Blackops/p/6122172.html
Copyright © 2011-2022 走看看