1. 程式人生 > >LCA【SP913】Qtree - Query on a tree II

LCA【SP913】Qtree - Query on a tree II

line 整數 描述 strong math getchar() pan script mat

Description

給定一棵n個點的樹,邊具有邊權。要求作以下操作:

DIST a b 詢問點a至點b路徑上的邊權之和

KTH a b k 詢問點a至點b有向路徑上的第k個點的編號

有多組測試數據,每組數據以DONE結尾。

Input

第一組數據包含一個整數\(T\),代表有\(T\)組測試數據。\(1\leq T \leq 25\)

對每一組測試數據:

  • 第一行一個整數\(N(n \leq 10000)\)
  • 接下來有\(N-1\)行,每一行描述樹上的一條邊\(a,b,c( c\leq 100000)\)
  • 接下來幾行操作包括\(DIST \ a \ b\),\(KTH \ a \ b \ k\)
  • \(DONE\)
    結尾

Output

對於每一個\(DIST\)\(KTH\)詢問輸出一行.

很明顯,LCA,但是難點就在於如何求出\(KTH\)對於的答案.

首先會存在兩種情況

一. \(k \leq depth[a]-depth[lca_{x,y}]+1\)

很明顯,這時第\(k\)個點必然在於\(x->lca_{x,y}\)的路徑上,我們只需要知道其深度即可倍增求取.

可求其深度為\(depth[a]-k+1\)

二. \(k > depth[a]-depth[lca_{x,y}]+1\)

這時,第\(k\)個點必然存在於\(y->lca_{x,y}\)的路徑上,但是如何求其深度卻是一個問題.

先設\(ans\)為第\(k\)個點的深度.

我們可以得到的信息是\(k\)必須要在\(y->lca_{x,y}\)

所以新的深度至少必須為\(k-(depth[x]-depth[lca_{x,y}]+1)\)

但是由於我們的\(lca_{x,y}\)不一定為\(1\)(這裏我以\(1\)為根)

所以原式子還需要加上一個\(depth[lca_{x,y}]\)

因此可以得到這樣一個式子
\[ ans=k-depth[x]+2*depth[lca_{x,y}]-1; \]
知道深度之後,直接倍增跳即可.

代碼

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define clear(a) memset(a,0,sizeof a)
#define N 10008
#define R register
using namespace std;
inline void in(int &x)
{
    int f=1;x=0;char s=getchar();
    while(!isdigit(s)){if(s=='-')f=-1;s=getchar();}
    while(isdigit(s)){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int T;
int n,head[N],tot;
struct cod{int u,v,w;}edge[N<<2];
inline void add(int x,int y,int z)
{
    edge[++tot].u=head[x];
    edge[tot].v=y;
    edge[tot].w=z;
    head[x]=tot;
}
int depth[N],f[N][21],dis[N];
void dfs(int u,int fa,int dist)
{
    f[u][0]=fa;dis[u]=dis[fa]+dist;depth[u]=depth[fa]+1;
    for(R int i=1;(1<<i)<=depth[u];i++)
        f[u][i]=f[f[u][i-1]][i-1];
    for(R int i=head[u];i;i=edge[i].u)
    {
        if(edge[i].v==fa)continue;
        dfs(edge[i].v,u,edge[i].w);
    }
}
inline int lca(int x,int y)
{
    if(depth[x]>depth[y])swap(x,y);
    for(R int i=17;i>=0;i--)
        if(depth[x]+(1<<i)<=depth[y])
            y=f[y][i];
    if(x==y)return y;
    for(R int i=17;i>=0;i--)
    {
        if(f[x][i]==f[y][i])continue;
        x=f[x][i],y=f[y][i];
    }
    return f[x][0];
}
char s[108];
inline int query(int x,int y,int k)
{
    R int la=lca(x,y);
    if(depth[x]-depth[la]+1>=k)
    {
        R int ans=depth[x]-k+1;
        for(R int i=17;i>=0;i--)
        {
            if(depth[x]-ans>=(1<<i))
                x=f[x][i];
        }
        return x;
    }
    else
    {
        R int ans=depth[la]*2+k-depth[x]-1;
        for(R int i=17;i>=0;i--)
            if((1<<i)<=depth[y]-ans)
                y=f[y][i];
        return y;
    }
}
int main()
{
    in(T);
    for(;T;T--)
    {
        in(n);
        tot=0;clear(head),clear(dis),clear(f);clear(depth);
        for(R int i=1,x,y,z;i<n;i++)
        {
            in(x),in(y),in(z);
            add(x,y,z);add(y,x,z);
        }
        dfs(1,0,0);
        for(R int x,y,la,k;;)
        {
            scanf("%s",s+1);
            if(s[2]=='O')break;
            if(s[2]=='I')
            {
                in(x),in(y);
                la=lca(x,y);
                printf("%d\n",dis[x]+dis[y]-2*dis[la]);
            }
            else
            {
                in(x),in(y),in(k);
                printf("%d\n",query(x,y,k));
            }
        }
    }
}

LCA【SP913】Qtree - Query on a tree II