【jzoj4899】【雪之国度】【最小生成树】【并查集按秩合并】

题目大意

给出一棵带点权的图,边权为点权之差的绝对值,询问两点之间两条不相交的路径,权值最大的权值是多少。

解题思路

先搞出最小生成树,再从小到大添加非树边,每添加一条就会形成一个边双连通分量,双连通分量里两两的答案就是添加边的价值(如果之前没连通),那么我们就可以用并查集把这个双连通分量并在一起,但是我们不路径压缩,这样可以让我们知道两个点最早什么时候连通(查看路径上的边最后加入的是哪条),这样就可以求出答案。

code

#include
#include
#include
#define LL long long
#define min(x,y) ((x
#define max(x,y) ((x>y)?x:y)
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
int const maxn=1e5,maxm=5*1e5;
int n,m,q,gra,w[maxn+10],fa[maxn+10],use[maxm+10],dep[maxn+10],begin[maxn+10],
to[maxn*2+10],next[maxn*2+10],f[maxn+10][20],h[maxn+10],len[maxn+10],
vis[maxn+10],inf=1e9;
struct rec{
    int u,v,w;
};
rec a[maxm+10];
bool cmp(rec x,rec y){
    return x.w<y.w;
}
void dfs(int now,int pre){
    for(int i=begin[now];i;i=next[i])
        if(to[i]!=pre){
            dep[to[i]]=dep[now]+1;
            f[to[i]][0]=now;
            dfs(to[i],now);
        }
}
int gett(int now){
    if(!fa[now])return now;
    return fa[now]=gett(fa[now]);
}
int get(int now){
    for(;fa[now];now=fa[now]);
    return now;
}
void insert(int u,int v){
    to[++gra]=v;
    next[gra]=begin[u];
    begin[u]=gra;
}
int lc(int u,int v){
    if(dep[u]17,0)
        if(dep[f[u][i]]>=dep[v])u=f[u][i];
    if(u==v)return u;
    fd(i,17,0)
        if(f[u][i]!=f[v][i]){u=f[u][i];v=f[v][i];}
    return f[u][0];
}
void connectt(int u,int v,int val){
    if(u==v)return;
    if(h[u]>h[v]){
        fa[v]=u;len[v]=val;
        h[u]=max(h[u],h[v]+1);
    }else{
        fa[u]=v;len[u]=val;
        h[v]=max(h[v],h[u]+1);
    }
}
void connect(int u,int v,int val){
    for(;u!=v;connectt(get(u),get(v),val),u=f[u][0]);
}
int qury(int u,int v){
    int i=u,ans=0;for(;fa[i];vis[i]=1,i=fa[i]);vis[i]=1;
    i=v;for(;!vis[i];ans=max(ans,len[i]),i=fa[i]);
    int j=u;for(;j!=i;ans=max(ans,len[j]),j=fa[j]);
    i=u;for(;fa[i];vis[i]=0,i=fa[i]);vis[i]=0;
    return ans;
}
int main(){
    //freopen("city.in","r",stdin);
    //freopen("city.out","w",stdout);
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
    scanf("%d%d%d",&n,&m,&q);
    fo(i,1,n)scanf("%d",&w[i]);
    fo(i,1,m){
        scanf("%d%d",&a[i].u,&a[i].v);
        a[i].w=abs(w[a[i].u]-w[a[i].v]);
    }
    sort(a+1,a+m+1,cmp);
    fo(i,1,m){
        int fu=gett(a[i].u),fv=gett(a[i].v);
        if(fu!=fv){
            fa[fu]=fv;use[i]=1;
            insert(a[i].u,a[i].v);
            insert(a[i].v,a[i].u);
        }
    }
    dep[1]=1;dfs(1,0);
    fo(j,1,17)fo(i,1,n)f[i][j]=f[f[i][j-1]][j-1];
    fo(i,1,n)fa[i]=0;
    fo(i,1,m)if(!use[i]){
        int fu=get(a[i].u),fv=get(a[i].v),lca=lc(a[i].u,a[i].v);
        if(fu!=fv){
            connect(a[i].u,lca,i);
            connect(a[i].v,lca,i);
        }
    }
    fo(i,1,q){
        int u,v;scanf("%d%d",&u,&v);
        if(get(u)!=get(v))printf("infinitely\n");
        else printf("%d\n",a[qury(u,v)].w);
    }
    return 0;
}

你可能感兴趣的:(jzoj,数据结构,图论)