P1967 货车运输

emmmm一开始是想到网络流来着???(最大流嘛233)

然后发现自己好像已经差不多忘完了???

于是打开题解,ctrl+f,输入网络流,好像没有题解,于是就老老实实想正解去了。

正解:

多组询问,想想网络流也要T(EK本来就慢,其它就不说了),所以一定是还有更简单的方法的!!!

对于每一个点(或者说路径),只有最小的那个边才对答案有影响(不是吗?)

慢着!这不是.....最小生成树?

于是就建最小生成树然后LCA。。。。。

于是愉快地选择kruskal和倍增lca。

于是这题就没什么了

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=500005;
int m,n,fat[maxn];
struct node
{
    int x,y,z;
}a[maxn];
struct edge
{
    int next,to,dis;
}e[maxn<<1];
int head[maxn],cnt,vis[maxn];
inline void addedge(int from,int to,int dis)
{
    e[++cnt].next=head[from];
    e[cnt].to=to;
    e[cnt].dis=dis;
    head[from]=cnt;
}
bool cmp(node x,node y)
{
    return x.z>y.z;
}
int find(int x)
{
    return fat[x]==x?x:fat[x]=find(fat[x]);
}
void kruskal()
{
    for(int i=1;i<=n;i++)
    fat[i]=i;
    for(int i=1;i<m;i++)
    {
        int fa=find(a[i].x);
        int fb=find(a[i].y);
        if(fa!=fb)
        {
            fat[fa]=fb;
            addedge(a[i].x,a[i].y,a[i].z);
            addedge(a[i].y,a[i].x,a[i].z);
        }
    }
}
int dep[maxn],f[25][maxn],w[25][maxn];
void dfs(int u,int deep)//预处理lca
{
    vis[u]=1;
    dep[u]=deep;
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(dep[v]!=0)
        continue;
        dfs(v,deep+1);
        f[0][v]=u;
        w[0][v]=e[i].dis;
    }
}
int lca(int a,int b)//lca
{
    if(find(a)!=find(b)) return -1;//不连通
    int ans=99999999;
    if(dep[a]<dep[b])
    swap(a,b);
    for(int i=20;i>=0;i--)
    {
        if(dep[b]<=dep[a]-(1<<i))
        {
            ans=min(ans,w[i][a]);
            a=f[i][a];
        }
    }
    if(a==b)
    return ans;
    for(int i=20;i>=0;i--)
    {
        if(f[i][a]!=f[i][b])
        {
            ans=min(ans,min(w[i][a],w[i][b]));
            a=f[i][a];
            b=f[i][b];
        }
    }
    ans=min(ans,min(w[0][a],w[0][b]));
    //printf("%d ",ans);
    return ans;
}
int main()
{
    //freopen("testdata.in","r",stdin);
    //freopen("1.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
    sort(a+1,a+m+1,cmp);
    kruskal();
    for(int i=1;i<=n;i++)
    {
        if(vis[i])
        continue;
        dfs(i,1);
        f[0][i]=i;
        w[0][i]=99999999;
    }
    for(int i=1;(1<<i)<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            f[i][j]=f[i-1][f[i-1][j]];
            w[i][j]=min(w[i-1][j],w[i-1][f[i-1][j]]);
        }
    }
    int q;
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        printf("%d\n",lca(x,y));
    }
    return 0;
}

(完)

posted @ 2019-08-13 22:25  阿基米德的澡盆  阅读(169)  评论(0编辑  收藏  举报