1. 程式人生 > >H - Tourism on Mars URAL - 2109 -LCA-線段樹

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;
    }
    

     

  •