1. 程式人生 > >bnuoj 24258 Journey(lca倍增法 弱校聯萌十一大決戰之背水一戰J)

bnuoj 24258 Journey(lca倍增法 弱校聯萌十一大決戰之背水一戰J)

題目連結

題意:在一棵n個節點的樹上,每條邊有權值,x->y的路徑長度為路徑上權值相加。現在在樹上新增一條u->v的邊,問q個詢問兩點間的最短路徑長度是否減少,減少了多少。

思路:新增邊之前,任意兩點間的路徑長度可通過倍增法求LCA在logn的時間求出,現在加了一條新邊用同樣的方法強行通過新邊進行比較即可。

<span style="font-size:14px;">//#pragma comment(linker, "/STACK:10240000000,10240000000")
#include<iostream>
#include<stdio.h>
#include<math.h>
#include <string>
#include<string.h>
#include<map>
#include<queue>
#include<set>
#include<utility>
#include<vector>
#include<algorithm>
#include<stdlib.h>
using namespace std;
#define eps 1e-8
#define pii pair<int,int>
#define inf 0x3f3f3f3f
#define rd(x) scanf("%d",&x)
#define rd2(x,y) scanf("%d%d",&x,&y)
#define ll long long int
#define mod 1000000007
#define maxn 100100
#define maxm 1000005
const int deg=20;
struct edge{
    int to,next,v;
}edge[maxn*2];
int head[maxn],tot;
int dis[maxn];
void addedge(int u,int v,int z){
    edge[tot].to=v;
    edge[tot].next=head[u];
    edge[tot].v=z;
    head[u]=tot++;
}
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
    memset(dis,0,sizeof dis);
}
int fa[maxn][deg];//fa[i][j]表示結點i的第2^j個祖先
int dep[maxn];//深度陣列

void bfs(int root){
    queue<int> que;
    dep[root]=0;
    fa[root][0]=root;
    que.push(root);
    while(!que.empty()){
        int tmp=que.front();
        que.pop();
        for(int i=1;i<deg;i++)
            fa[tmp][i]=fa[fa[tmp][i-1]][i-1];
        for(int i=head[tmp];i!=-1;i=edge[i].next){
            int v=edge[i].to;
            if(v==fa[tmp][0]) continue;
            dis[v]=dis[tmp]+edge[i].v;
            dep[v]=dep[tmp]+1;
            fa[v][0]=tmp;
            que.push(v);
        }
    }
}
int lca(int u,int v){
    if(dep[u]>dep[v]) swap(u,v);
    int hu=dep[u],hv=dep[v];
    int tu=u,tv=v;
    for(int det=hv-hu,i=0;det;det>>=1,i++)
        if(det&1) tv=fa[tv][i];
    if(tu==tv) return tu;
    for(int i=deg-1;i>=0;i--){
        if(fa[tu][i]==fa[tv][i]) continue;
        tu=fa[tu][i];
        tv=fa[tv][i];
    }
    return fa[tu][0];
}
int d(int u,int v){
    return dis[u]+dis[v]-2*dis[lca(u,v)];
}
int t,n,tt,q,x,y,z,u,v;
int main()
{
    rd(t);tt=0;
    while(t--){
        init();
        rd2(n,q);
        for(int i=1;i<n;i++){
            scanf("%d%d%d",&x,&y,&z);
            addedge(x,y,z);
            addedge(y,x,z);
        }
        bfs(1);
        scanf("%d%d%d",&x,&y,&z);
        printf("Case #%d:\n",++tt);
        while(q--){
            rd2(u,v);
            int l1=d(u,x)+z+d(v,y);//強行通過新邊
            int l2=d(u,y)+z+d(v,x);
            int l=d(u,v);//原來在樹上的路徑
            l1=min(l1,l2);
            if(l1<=l) printf("%d\n",l-l1);
            else printf("0\n");
        }
    }
    return 0;
}
</span>