题目描述
给出一张n个点,0条边的图,在第i个时刻(下标从1开始),向图中加入第i条无向边。
有q次询问,每次询问u,v两个点最早在什么时刻连通。
输入
输出
样例输入
4 6
1 3
3 4
1 4
2 4
2 3
1 2
4
1 2
3 4
1 4
2 3
样例输出
4
2
2
4
提示
解题思路
看到题目的第一感觉,发现数据是出奇地大,但这一道题目,肯定是可以构图的。(关键我连构图这一节都分析了好久才想到,而且还放弃并查集用了最短路)。事实上,此题就是需要并查集与LCA,图中的边很多,我们利用并查集其实也可以消去一些没有用的边,最后只可能有N-1条有效边,大大减小了时间复杂度。最后问连通没有,我们仅仅需要求出这一一段树上路径的最短路。
我们处理并查集时,用秩优化,这里特别注意,不要用路径压缩,路径压缩可以说是把树全部打乱了,对我们来说这是致命的,我们用秩优化,因而树就是一棵长度为logn的树。
但树其实是经过并查集处理,是很奇怪的,我们可以找到根节点,再进行dfs,真正构造出一棵树。求到深度,距离。
构造完之后,就很水了,可以暴力求树上最大路径,还可以倍增,速度似乎要快一点。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#include<cstdlib>
#include<algorithm>
using namespace std;
struct edge{
int u,v;
edge(){};
edge(int U,int V){
u = U,v = V;
}
};
int n,m,fa[50005],rank1[50005],q,mov[50005],dis[50005];
vector <edge>G[50005];
void makeset(int x){
for (int i = 1;i <= x; i ++){
fa[i] = i;
rank1[i] = 1;
}
}
int findset(int x){
while (x != fa[x])
x = fa[x];
return x;
}
void unionset(int a,int b,int time){
int t = findset(a);
int t1 = findset(b);
if (t == t1)
return ;
G[t].push_back(edge(t1,time));
G[t1].push_back(edge(t,time));
if (rank1[t] > rank1[t1])
fa[t1] = t;
else {
fa[t] = t1;
if (rank1[t] == rank1[t1])
rank1[t1] ++;
}
}
void dfs(int step){
int x = G[step].size();
for (int i = 0;i < x; i ++){
if (!mov[G[step][i].u]){
mov[G[step][i].u] = 1;
rank1[G[step][i].u] = rank1[step] + 1;
dis[G[step][i].u] = G[step][i].v;
dfs(G[step][i].u);
}
}
}
int lca(int u,int v){
int ans = 0;
while (rank1[u] > rank1[v]){
ans = max(dis[u],ans);
u = fa[u];
}
while (rank1[v] > rank1[u]){
ans = max(dis[v],ans);
v = fa[v];
}
while (u != v){
ans = max(dis[u],ans);
u = fa[u];
ans = max(dis[v],ans);
v = fa[v];
}
return ans;
}
int main(){
scanf ("%d%d",&n,&m);
makeset(n);
for (int i = 1 ;i <= m;i ++){
int a,b;
scanf ("%d%d",&a,&b);
unionset(a,b,i);
}
for (int i = 1;i <= n;i ++){
if (fa[i] == i){
mov[i] = 1;
rank1[i] = 1;
dfs(i);
}
}
scanf ("%d",&q);
while (q --){
int a,b;
scanf ("%d%d",&a,&b);
if (findset(a) != findset(b))
printf("-1
");
else if (a == b)
printf("0
");
else
printf("%d
",lca(a,b));
}
}
总结
我表示这道题考试时候是摸到了一点思路的,但确实是没想到树,构造这一棵树才是最为关键的。树构造出来,之后的答案就可以很好很轻松地做了。