题目大意
给出一棵带点权的图,边权为点权之差的绝对值,询问两点之间两条不相交的路径,权值最大的权值是多少。
解题思路
先搞出最小生成树,再从小到大添加非树边,每添加一条就会形成一个边双连通分量,双连通分量里两两的答案就是添加边的价值(如果之前没连通),那么我们就可以用并查集把这个双连通分量并在一起,但是我们不路径压缩,这样可以让我们知道两个点最早什么时候连通(查看路径上的边最后加入的是哪条),这样就可以求出答案。
code
,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;
}