1. 程式人生 > 實用技巧 >習題:Daleks' Invasion (hard)(LCA&冰茶姬)

習題:Daleks' Invasion (hard)(LCA&冰茶姬)

題目

傳送門

思路

我們隨便找一棵最小生成樹

之後將邊分成兩種:樹邊和非樹邊、

如果是非樹邊很好處理,直接LCA求最大值即可

考慮不是樹邊的情況,

如果把這條樹邊切開,有很多邊連線兩個連通塊,我們所需要的知道的是除了這條邊另外的所有邊的最小值

這些最小值可以用樹鏈剖分暴力維護,

當然也可以將邊排序之後用類似於冰茶姬的方法進行維護

程式碼

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
namespace ufs
{
    int fa[100005];
    void makeset(int n)
    {
        for(int i=1;i<=n;i++)
            fa[i]=i;
    }
    int findset(int x)
    {
        if(fa[x]==x)
            return x;
        return fa[x]=findset(fa[x]);
    }
    void merge(int u,int v)
    {
        int a=findset(u);
        int b=findset(v);
        fa[a]=b;
    }
}
using namespace ufs;
struct edge
{
    int u,v;
    long long w;
    int id;
    friend bool operator < (const edge &a,const edge &b)
    {
        return a.w<b.w;
    }
}a[1000005];
struct node
{
    int e;
    long long w;
};
int n,m;
int fath[100005],dep[100005],dp_ind[100005][25];
long long dp_w[100005][25];
long long ans[1000005],w[100005],val[100005];
bool vis[1000005];
vector<node> g[100005];
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]=max(dp_w[u][i-1],dp_w[dp_ind[u][i-1]][i-1]);
    }
    for(int i=0;i<g[u].size();i++)
    {
        int v=g[u][i].e;
        if(v!=fa)
        {
            fath[v]=u;
            dp_ind[v][0]=u;
            dp_w[v][0]=g[u][i].w;
            w[v]=g[u][i].w;
            dfs(v,u);
        }
    }
}
long long lca(int u,int v)
{
    long long maxx=0;
    if(u==v)
        return 0;
    if(dep[u]>dep[v])
        swap(u,v);
    for(int i=20;i>=0;i--)
        if(dep[u]<=dep[dp_ind[v][i]])
        {
            maxx=max(maxx,dp_w[v][i]);
            v=dp_ind[v][i];
        }    
    if(u==v)
        return maxx;
    for(int i=20;i>=0;i--)
        if(dp_ind[u][i]!=dp_ind[v][i])
        {
            maxx=max(maxx,max(dp_w[u][i],dp_w[v][i]));
            u=dp_ind[u][i];
            v=dp_ind[v][i];
        }
    return max(maxx,max(dp_w[u][0],dp_w[v][0]));
}
void col(int u,int v,long long s)
{
    while(u!=v)
    {
        if(dep[u]>dep[v])
            swap(u,v);
        val[v]=s;
        merge(v,fath[v]);
        v=findset(v);
    }
}
int main()
{
    memset(ans,-1,sizeof(ans));
    memset(val,-1,sizeof(val));
    cin>>n>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>a[i].u>>a[i].v>>a[i].w;
        a[i].id=i;
    }
    sort(a+1,a+m+1);
    makeset(n);
    for(int i=1;i<=m;i++)
    {
        if(findset(a[i].u)!=findset(a[i].v))
        {
            merge(a[i].u,a[i].v);
            vis[i]=1;
            g[a[i].u].push_back((node){a[i].v,a[i].w});
            g[a[i].v].push_back((node){a[i].u,a[i].w});
        }
    }
    dfs(1,0);
    makeset(n);
    for(int i=1;i<=m;i++)
        if(dep[a[i].u]>dep[a[i].v])
            swap(a[i].u,a[i].v);
    for(int i=1;i<=m;i++)
        if(vis[i]==0)
            col(findset(a[i].u),findset(a[i].v),a[i].w);
    for(int i=1;i<=m;i++)
    {
        if(vis[i]==0)
            ans[a[i].id]=lca(a[i].u,a[i].v);
        else
            ans[a[i].id]=val[a[i].v];
    }
    for(int i=1;i<=m;i++)
        if(ans[i]==-1)
            cout<<"1000000000\n";
        else
            cout<<ans[i]<<'\n';
    return 0;
}