给定 n 个点, m 条边的无向图。每个点有点权 wi ,一条边 (x,y) 的边权定义为 |wx−wy| 。
有 q 询问,每次询问两个点 (x,y) ,如果 x 和 y 之间存在至少两条互不相交(没有重复边)的路径,那么输出这两条路径上边权的最大值(如果有多对路径,选择最小的),否则输出 −1 。
3≤n≤105,3≤m≤5×105,1≤q≤105
考虑一种最暴力的做法,按边权从小到大插入边,动态维护边双连通分量。连通分量内的答案可以瞎处理。然而这样很难维护。
怎么办呢?用最小生成树来维护一个联通性,这样然后在树上可以更方便的处理边双内路径的最大权值。我们可能会加入某些边使得它有环,那么环内权值就要变成加入这条边的权值(加入边肯定更大)。但是修改过一次的边我们就不能再修改了,因为显然它达到了条件且不会更优。因此我们使用并查集来将所有修改过的点并在一起,这样修改时就可以暴力沿着并查集父亲修改了。
处理询问的话,倍增查询路径最大值即可。
时间复杂度 O(nlog2n) 。
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
int buf[30];
void write(int x)
{
if (x<0) x=-x,putchar('-');
for (;x;x/=10) buf[++buf[0]]=x%10;
if (!buf[0]) buf[++buf[0]]=0;
for (;buf[0];) putchar('0'+buf[buf[0]--]);
}
const int N=100050;
const int M=500050;
const int E=N<<1;
const int LGN=17;
struct edge
{
int x,y,l;
}e[M];
bool operator<(edge a,edge b){return a.l<b.l;}
int fa[N],deep[N],last[N],w[N];
int f[N][LGN],anc[N][LGN];
int tov[E],nxt[E],len[E];
int n,m,q,tot,lgn,ans;
bool chosen[M];
int getfather(int son){return fa[son]==son?son:fa[son]=getfather(fa[son]);}
void insert(int x,int y,int z){tov[++tot]=y,len[tot]=z,nxt[tot]=last[x],last[x]=tot;}
void dfs(int x)
{
for (int i=last[x],y;i;i=nxt[i])
if ((y=tov[i])!=anc[x][0])
anc[y][0]=x,deep[y]=deep[x]+1,f[y][0]=len[i],dfs(y);
}
void pre()
{
lgn=trunc(log(n)/log(2));
for (int j=1;j<=lgn;j++)
for (int i=1;i<=n;i++)
anc[i][j]=anc[anc[i][j-1]][j-1],f[i][j]=max(f[i][j-1],f[anc[i][j-1]][j-1]);
}
int adjust(int x,int d)
{
for (int i=lgn;i>=0;i--)
if (deep[anc[x][i]]>=d) ans=max(ans,f[x][i]),x=anc[x][i];
return x;
}
void getans(int x,int y)
{
ans=0;
if (deep[x]>deep[y]) swap(x,y);
y=adjust(y,deep[x]);
if (x==y) return;
for (int i=lgn;i>=0;i--)
if (anc[x][i]!=anc[y][i]) ans=max(ans,max(f[x][i],f[y][i])),x=anc[x][i],y=anc[y][i];
ans=max(ans,max(f[x][0],f[y][0])),x=anc[x][0],y=anc[y][0];
}
int main()
{
freopen("city.in","r",stdin),freopen("city.out","w",stdout);
n=read(),m=read(),q=read();
for (int i=1;i<=n;i++) w[i]=read(),fa[i]=i;
for (int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].l=abs(w[e[i].x]-w[e[i].y]);
sort(e+1,e+1+m);
for (int i=1,x,y,fx,fy;i<=m;i++)
{
fx=getfather(x=e[i].x),fy=getfather(y=e[i].y);
if (fx!=fy)
{
chosen[i]=1;
fa[fy]=fx;
insert(x,y,e[i].l),insert(y,x,e[i].l);
}
}
anc[1][0]=0,deep[1]=1,dfs(1);
for (int i=1;i<=n;i++) fa[i]=i;
for (int i=1,x,y;i<=m;i++)
if (!chosen[i])
for (x=getfather(e[i].x),y=getfather(e[i].y);x!=y;x=getfather(x))
{
if (deep[x]<deep[y]) swap(x,y);
f[x][0]=max(e[i].l,f[x][0]);
fa[x]=anc[x][0];
}
pre();
for (int x,y;q--;)
{
x=read(),y=read();
if (getfather(x)!=getfather(y)||x==y) printf("infinitely\n");
else getans(x,y),write(ans),putchar('\n');
}
fclose(stdin),fclose(stdout);
return 0;
}