【NOIP 2013】货车运输(Kruskal+lca)

传送门

Solution:

一辆车的载重,取决于他到终点上的路的载重最小值,最小值越大,装的就越多

考虑如何找路径,如果bfs或者dfs的话,TLE。

这时想到,我们可以做一颗最大生成树(按照权值从大到小排序),在生成树的基础上,两点之间都是联通的,而且载重也是最优的。

这时考虑如何在生成树上找到两点的路径,一棵树,自然而然地就想到了LCA,然后就AC了。

#include
#define N 10005
#define M 50005
using namespace std;
int n,m,father[N],tot,first[N],dep[N],up[N][22],w[N][22];
const int INF=0x7fffffff;
struct A
{
    int from,to,val;
}a[M];
struct node
{
    int to,next,val;
}edge[2*M];
inline int getfather(int x)
{
    if(father[x]==x)    return x;
    father[x]=getfather(father[x]);
    return father[x];
}
inline void addedge(int x,int y,int z)
{
    tot++;
    edge[tot].to=y;
    edge[tot].next=first[x];
    edge[tot].val=z;
    first[x]=tot;
}
inline bool cmp(const A &x,const A &y)
{
    return x.val>y.val;
}
void Init()
{
    for(int i=1;i<=n;i++)
    {
        father[i]=i;
    }   
}
void kruskal()
{
    int k=0;
    for(int i=1;i<=m;i++)
    {
        int x=a[i].from;
        int y=a[i].to;
        int ax=getfather(x);
        int bx=getfather(y);
        if(ax!=bx)
        {
            father[ax]=bx;
            k++;
            addedge(x,y,a[i].val);
            addedge(y,x,a[i].val);
        }
        if(k==n-1)  break;
    }
}
inline void dfs(int now)
{
    for(int u=first[now];u;u=edge[u].next)
    {
        int vis=edge[u].to;
        if(dep[vis])    continue;
        dep[vis]=dep[now]+1;
        up[vis][0]=now;
        w[vis][0]=edge[u].val;
        dfs(vis);
    }
}
inline int lca(int x,int y)
{
    if(getfather(x)!=getfather(y))  return -1;
    if(dep[x]=0;i--)//注意是到0,而不是1,是1就WA了
    {
        if(dep[up[x][i]]>=dep[y])
        {
            ans=min(ans,w[x][i]);
            x=up[x][i];
        }
    }
    if(x==y)    return ans;
    for(int i=20;i>=0;i--) 
    {
        if(up[x][i]!=up[y][i])
        {
            ans=min(ans,min(w[x][i],w[y][i]));
            x=up[x][i];
            y=up[y][i];
        }
    }
    ans=min(ans,min(w[x][0],w[y][0]));
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    cin>>n>>m;
    Init();
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        cin>>x>>y>>z;
        a[i].from=x,a[i].to=y,a[i].val=z;
    }
    sort(a+1,a+m+1,cmp);
    kruskal();
    
    for(int i=1;i<=n;i++)//由于不确定生成树包含哪些点 所以要一个一个扫描 
    {
        if(!dep[i])
        {
            dep[i]=1;
            dfs(i);
            up[i][0]=i;
            w[i][0]=INF;
        }
    }
    
    for(int j=1;j<=20;j++)
    {
        for(int i=1;i<=n;i++)
        {
            up[i][j]=up[up[i][j-1]][j-1];
            w[i][j]=min(w[i][j-1],w[up[i][j-1]][j-1]);
        }
    }
    int q;
    cin>>q;
    for(int i=1;i<=q;i++)
    {
        int x,y;
        cin>>x>>y;
        cout<

你可能感兴趣的:(【NOIP 2013】货车运输(Kruskal+lca))