1. 程式人生 > >XJOI 修繕計劃(最小生成樹,LCA)

XJOI 修繕計劃(最小生成樹,LCA)

() clu spf main logs pre lca line amp

題面非常簡單,給你一張圖

一條路徑的權是指路徑上最長邊的權值

詢問兩個點之間所有路徑中權值最小的

技術分享

技術分享

技術分享

技術分享

然後我傻乎乎地打了一個暴力SPFA

#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int N=10010,M=200010;
int dis[N][N],b[M],c[M],ne[M],fi[N],cc[N],k,x,y,in[N],n,m,z,q;
inline void add(const int &x,const int
&y,const int &z){ b[++k]=y; c[k]=z; ne[k]=fi[x]; fi[x]=k; } inline int max(const int &x,const int &y){ return x>y?x:y; } void SPFA(int s){ queue<int>q; q.push(s); dis[s][s]=0; while (!q.empty()){ x=q.front(); q.pop(); in[x]=0;
for (int j=fi[x]; j; j=ne[j]) if (max(dis[s][x],c[j])<dis[s][b[j]]){ dis[s][b[j]]=max(dis[s][x],c[j]); if (!in[b[j]]){ q.push(b[j]); in[b[j]]=1; } } } } int main(){ scanf("%d%d",&n,&m);
for (int i=1; i<=n; i++) scanf("%d",&cc[i]); for (int i=1; i<=m; i++){ scanf("%d%d%d",&x,&y,&z); add(x,y,z+cc[x]+cc[y]); add(y,x,z+cc[x]+cc[y]); } memset(dis,0x3f3f3f,sizeof(dis)); for (int i=1; i<=n; i++) SPFA(i); scanf("%d",&q); while (q--){ scanf("%d%d",&x,&y); printf("%d\n",dis[x][y]); } }

考試結束前10分鐘才意識到正解,為時已晚.

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int N=10010,M=200010,INF=0x3f3f3f;
struct edge{
    int x,y,z;
}e[M];
int b[M],c[M],ne[M],fi[N],cc[N],fa[N],k,x,y,n,m,z,q,f[N][21],maxf[N][21],deep[N];
inline void add(const int &x,const int &y,const int &z){
    b[++k]=y; c[k]=z; ne[k]=fi[x]; fi[x]=k;
}
bool cmp(edge x,edge y){
    return x.z<y.z;
}
inline int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}
void dfs(int x){
    for (int j=fi[x]; j; j=ne[j])
    if (b[j]!=f[x][0]){
        f[b[j]][0]=x;
        maxf[b[j]][0]=c[j];
        deep[b[j]]=deep[x]+1;
        dfs(b[j]);
    }
}
int getlca(int x,int y){
    int res=0;
    if (deep[x]>deep[y]) x^=y^=x^=y;
    for (int j=20; j>=0; j--)
    if (deep[f[y][j]]>=deep[x]){
        res=max(res,maxf[y][j]);
        y=f[y][j];
    }
    if (x==y) return res;
    for (int j=20; j>=0; j--)
    if (f[x][j]!=f[y][j]){
        res=max(max(res,maxf[x][j]),maxf[y][j]);
        x=f[x][j];
        y=f[y][j];
    }
    res=max(res,max(maxf[x][0],maxf[y][0]));
    return res;
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1; i<=n; i++) scanf("%d",&cc[i]);
    for (int i=1; i<=m; i++){
        scanf("%d%d%d",&x,&y,&z);
        e[i].x=x;
        e[i].y=y;
        e[i].z=z+cc[x]+cc[y];
    }
    sort(e+1,e+m+1,cmp);
    for (int i=1; i<=n; i++) fa[i]=i;
    for (int i=1; i<=m; i++){
        x=find(e[i].x); y=find(e[i].y);
        if (x!=y){
            fa[x]=y;
            add(e[i].x,e[i].y,e[i].z);
            add(e[i].y,e[i].x,e[i].z);
        }
    }
    dfs(1);
    for (int j=1; j<=20; j++)
    for (int i=1; i<=n; i++){
        f[i][j]=f[f[i][j-1]][j-1];
        maxf[i][j]=max(maxf[i][j-1],maxf[f[i][j-1]][j-1]);
    }
    scanf("%d",&q);
    while (q--){
        scanf("%d%d",&x,&y);
        printf("%d\n",getlca(x,y));
    }
}

慘啊

XJOI 修繕計劃(最小生成樹,LCA)