1. 程式人生 > 實用技巧 >習題:The Shortest Statement(dij&LCA)

習題:The Shortest Statement(dij&LCA)

題目

傳送門

思路

注意到邊的數量很特殊,只比點的數量多了20不到

先建一顆生成樹,如果不用多的邊,那每兩個的之間的距離就可以直接LCA來求

考慮如果多的邊有用,設這些多的邊的端點的集合為P,那麼一定是從起點到P中的某一個元素,再到P中的另一個元素,再到終點,所以對P中的每一個元素進行一次dij,

最後的答案跟LCA進行比較即可

程式碼

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
namespace IO
{
    void read(int &x)
    {
        x=0;
        int f=1;
        char c=getchar();
        while('0'>c||c>'9')
        {
            if(c=='-')
                f=-1;
            c=getchar();
        }
        while('0'<=c&&c<='9')
        {
            x=(x<<3)+(x<<1)+c-'0';
            c=getchar();
        }
        x*=f;
    }
    void read(long long &x)
    {
        x=0;
        int f=1;
        char c=getchar();
        while('0'>c||c>'9')
        {
            if(c=='-')
                f=-1;
            c=getchar();
        }
        while('0'<=c&&c<='9')
        {
            x=(x<<3)+(x<<1)+c-'0';
            c=getchar();
        }
        x*=f;
    }
    void write(int x)
    {
        if(x<10)
            putchar(x+'0');
        else
        {
            write(x/10);
            putchar(x%10+'0');
        }
    }
    void write(long long x)
    {
        if(x<10)
            putchar(x+'0');
        else
        {
            write(x/10);
            putchar(x%10+'0');
        }
    }
}
using namespace IO;
struct node
{
    int e;
    long long w;
    friend bool operator < (const node &a,const node &b)
    {
        return a.w>b.w;
    }
};
int n,m,Q;
int dp_ind[100005][25],dep[100005];
long long dp_w[100005][25],dis[45][100005];
bool used[100005],vis[100005];
vector<int> p;
vector<node> g[100005];
priority_queue<node> q;
void dfs(int u,int fa)
{
    dep[u]=dep[fa]+1;
    for(int i=1;i<=20;i++)
    {
        dp_ind[u][i]=dp_ind[dp_ind[u][i-1]][i-1];
        dp_w[u][i]=dp_w[u][i-1]+dp_w[dp_ind[u][i-1]][i-1];
    }
    used[u]=1;
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i].e;
        if(v==fa)
            continue;
        else if(used[v])
        {
            if(vis[u]==0)
            {
                vis[u]=1;
                p.push_back(u);
            }
            if(vis[v]==0)
            {
                vis[v]=1;
                p.push_back(v);
            }
        }
        else
        {
            dp_ind[v][0]=u;
            dp_w[v][0]=g[u][i].w;
            dfs(v,u);
        }
    }
}
long long lca(int u,int v)
{
    long long w=0;
    if(u==v)
        return w;
    if(dep[u]>dep[v])
        swap(u,v);
    for(int i=20;i>=0;i--)
        if(dep[u]<=dep[dp_ind[v][i]])
        {
            w=w+dp_w[v][i];
            v=dp_ind[v][i];
        }
    if(u==v)
        return w;
    for(int i=20;i>=0;i--)
    {
        if(dp_ind[u][i]!=dp_ind[v][i])
        {
            w=w+dp_w[u][i];
            w=w+dp_w[v][i];
            u=dp_ind[u][i];
            v=dp_ind[v][i];
        }
    }
    return w+dp_w[u][0]+dp_w[v][0];
}
void dij(int s,long long *dis)
{
    q.push((node){s,0});
    while(!q.empty())
    {
        node t=q.top();
        q.pop();
        if(t.w>dis[t.e])
            continue;
        dis[t.e]=t.w;
        for(int i=0;i<g[t.e].size();i++)
        {
            int v=g[t.e][i].e;
            if(t.w+g[t.e][i].w<dis[v])
                q.push((node){v,t.w+g[t.e][i].w});
        }
    }
}
int main()
{
    memset(dis,0x3f,sizeof(dis));
    read(n);read(m);
    for(int i=1,u,v;i<=m;i++)
    {
        long long w;
        read(u);read(v);read(w);
        g[u].push_back((node){v,w});
        g[v].push_back((node){u,w});
    }
    dfs(1,0);
    for(int i=0;i<p.size();i++)
        dij(p[i],dis[i]);
    read(Q);
    for(int i=1,u,v;i<=Q;i++)
    {
    	read(u);read(v);
        long long ans=(1ll<<60);
        for(int i=0;i<p.size();i++)
            for(int j=0;j<p.size();j++)
                ans=min(ans,dis[i][u]+dis[i][p[j]]+dis[j][v]);
        write(min(ans,lca(u,v)));
        putchar('\n');
    }
    return 0;
}