H - Tourism on Mars URAL - 2109 -LCA-线段树

  • H - Tourism on Mars

     URAL - 2109 
  • 题意:给你 n 个点,接下来 n-1 行,每行输入 u, v 代表 u 点和 v 点无向边。 有 q 次询问。 
  • u 到 v 的道路中,距离 1 点最近的点,是main attraction 点。 
  • 每次询问输入 u, v 问,u 到 u+1 main attraction 点,u+1 到 u+2重要的点…. v-1 到 v 重要的点中哪个点距离 1最更近.
  • 思路:n个点,n-1条边,是一棵树,所以任意两点最短路径唯一,而且这条最短路径就是这两个点分别到它们的公共祖先,
  • 那么任意两点之间的路径上距离1最近的点,一定是他们的最近公共祖先,所以利用倍增求LCA预处理出他们的公共祖先
  • 然后线段树维护一下一段区间内距离1最近的main attraction 点,由于判断与1的远近需要deep深度来判断,所以维护了一下
  • 深度的最小值,还需要知道是哪个点同时维护了一下距离1最近的点,然后每个节点存的是i与i+1的公共祖先,所以线段树
  • 只需要建一个1-n-1的即可,这样的话输入n==1是需要特判否则直接建树会RE,感谢郑延亮,tql-http://zyl1213.top/blog/
  • #include<bits/stdc++.h>
    using namespace std;
    #define maxn 1234567
    int n,q,u,v,cnt,head[maxn],ans;
    int deep[maxn],dp[maxn][30],id;
    struct tre
    {
        int l,r,depth,fa;
    } tree[maxn*4];
    struct node
    {
        int v,to;
    } edge[maxn];
    void add(int u,int v)
    {
        edge[++cnt].v=v;
        edge[cnt].to=head[u];
        head[u]=cnt;
    }
    void dfs(int cur,int pre)
    {
        deep[cur]=deep[pre]+1;
        dp[cur][0]=pre;
        for(int i=1; (1<<i)<=deep[cur]; i++)
            dp[cur][i]=dp[dp[cur][i-1]][i-1];
        for(int i=head[cur]; i!=-1; i=edge[i].to)
            if(edge[i].v!=pre)
                dfs(edge[i].v,cur);
    }
    int lca(int x,int y)
    {
        if(deep[x]<deep[y])
            swap(x,y);
        for(int i=22; i>=0; i--)
            if(deep[x]-(1<<i)>=deep[y])
                x=dp[x][i];
        if(x==y)return x;
        for(int i=22; i>=0; i--)
            if(dp[x][i]!=dp[y][i])
            {
                x=dp[x][i];
                y=dp[y][i];
            }
        return dp[x][0];
    }
    void up(int root)
    {
        if(tree[root*2].depth<tree[root*2+1].depth)
        {
            tree[root].depth=tree[root*2].depth;
            tree[root].fa=tree[root*2].fa;
        }
        else
        {
            tree[root].depth=tree[root*2+1].depth;
            tree[root].fa=tree[root*2+1].fa;
        }
    }
    void build(int root,int l,int r)
    {
        tree[root].l=l;
        tree[root].r=r;
        if(l==r)
        {
            tree[root].fa=lca(l,l+1);
            tree[root].depth=deep[tree[root].fa];
            return ;
        }
        int mid=(l+r)/2;
        build(root*2,l,mid);
        build(root*2+1,mid+1,r);
        up(root);
    }
    void query(int root,int l,int r)
    {
        if(tree[root].l==l&&tree[root].r==r)
        {
            if(tree[root].depth<ans)
            {
                ans=tree[root].depth;
                id=tree[root].fa;
            }
            return ;
        }
        int mid=(tree[root].l+tree[root].r)/2;
        if(l>mid)query(root*2+1,l,r);
        else if(r<=mid)query(root*2,l,r);
        else
        {
            query(root*2,l,mid);
            query(root*2+1,mid+1,r);
        }
    }
    int main()
    {
        deep[0]=0;
        memset(head,-1,sizeof(head));
        scanf("%d",&n);
        for(int i=1; i<n; i++)
        {
            scanf("%d%d",&u,&v);
            add(u,v);
            add(v,u);
        }
        scanf("%d",&q);
        if(n==1)
        {
            while(q--)
            {
                scanf("%d%d",&u,&v);
                printf("1\n");
            }
            return 0;
        }
        dfs(1,0);
        build(1,1,n-1);
        while(q--)
        {
            ans=1e8;
            scanf("%d%d",&u,&v);
            if(u==v)printf("%d\n",u);
            else
            {
                query(1,u,v-1);
                printf("%d\n",id);
            }
        }
        return 0;
    }
    
  •  

猜你喜欢

转载自blog.csdn.net/BePosit/article/details/84586171
今日推荐