正题
题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1743
题目大意
nnn个点mmm条边的一张图,每次询问要求找出x,yx,yx,y直接的两条不重路径的最大值最小。
解题思路
首先第一条路径肯定是最小生成树上的路径,所以我们先求出最小生成树。
然后对与剩下的边我们从小到大加入图中,每条边(u,v)(u,v)(u,v)会作为在(u,v)(u,v)(u,v)之间的所有点对的第二条路径。也就是对与一个点对(x,y)(x,y)(x,y)中间有经过(u,v)(u,v)(u,v)的路径那么都会取到这条边的值,也就是将(u,v)(u,v)(u,v)这条路径取minminmin,然后询问时就是询问(x,y)(x,y)(x,y)之间的最大值。
而且因为是从小到大加入的,所有如果一个位置之间已经加入过就不需要管,所以我们可以开一个并查集记录跳到最上面没有加入的点。
时间复杂度O(mlogn)O(m\log n)O(mlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10;
struct node{int x,y;
}e[N];
struct edge_node{int to,next;
}a[N];
int n,m,q,tot,val[N],fa[N],ls[N];
int f[N][20],w[N][20],dep[N];
bool vis[N];
bool cmp(node x,node y)
{return abs(val[x.x]-val[x.y])<abs(val[y.x]-val[y.y]);}
int find(int x)
{return (fa[x]==x)?(x):(fa[x]=find(fa[x]));}
void addl(int x,int y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return;
}
void dfs(int x,int fa){if(x==341)x++,x--;f[x][0]=fa;dep[x]=dep[fa]+1;for(int i=ls[x];i;i=a[i].next){int y=a[i].to;if(y==fa)continue;dfs(y,x);}return;
}
int LCA(int x,int y){int ans=0;if(dep[x]>dep[y])swap(x,y);for(int i=18;i>=0;i--)if(dep[f[y][i]]>=dep[x])ans=max(ans,w[y][i]),y=f[y][i];if(x==y)return ans;for(int i=18;i>=0;i--)if(f[y][i]!=f[x][i])ans=max(ans,max(w[x][i],w[y][i])),x=f[x][i],y=f[y][i];return max(ans,max(w[x][0],w[y][0]));
}
int main()
{scanf("%d%d%d",&n,&m,&q);for(int i=1;i<=n;i++)scanf("%d",&val[i]),fa[i]=i;for(int i=1;i<=m;i++)scanf("%d%d",&e[i].x,&e[i].y);sort(e+1,e+1+m,cmp);for(int i=1;i<=m;i++){int x=find(e[i].x),y=find(e[i].y);if(x==y)continue;addl(e[i].x,e[i].y);addl(e[i].y,e[i].x);fa[x]=y;vis[i]=1;}dfs(1,0);for(int i=1;i<=n;i++)fa[i]=i,w[i][0]=2147483647;for(int i=1;i<=m;i++){if(vis[i])continue;int x=find(e[i].x),y=find(e[i].y);while(x!=y){if(dep[x]<dep[y])swap(x,y);w[x][0]=abs(val[e[i].x]-val[e[i].y]); fa[x]=f[x][0];x=find(x);}}for(int j=1;j<=18;j++)for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1],w[i][j]=max(w[i][j-1],w[f[i][j-1]][j-1]);while(q--){int x,y;scanf("%d%d",&x,&y);int ans=LCA(x,y);if(ans==2147483647)printf("infinitely\n");else printf("%d\n",ans);}return 0;
}