[codeforces] Gym - 100814C Connecting Graph (並查集+LCA)
題目鏈接:100814C Connecting Graph
題目大意:
給定n個點, m個操作, 操作由兩種形式
數據範圍:
解題思路:
兩個點什麼時候最早連通就是這兩個點之間的最大值, 可以想到用LCA+倍增維護最大值。 題中並沒有說肯定是棵樹, 但是如果兩個點之前已經聯通了, 當前這條邊就沒有必要加進去了(有點最小生成樹的感覺), 所以最後肯定生成的是一個樹。
這道題的主要思想就是用LCA + 倍增維護最大值。
代碼:
/**********************************************
*Author* :ZZZZone
*reated Time* : 2017/8/8 20:57:14
*ended Time* : 2017/8/9 12:05:21
*********************************************/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
const int MaxN = 1e5;
int fa[MaxN + 5], dis[MaxN + 5];
int up[MaxN + 5][25], Max[MaxN + 5][25];
vector<PII>edge[MaxN + 5];
struct NODE{
int p, u, v;
}q[MaxN + 5];
int T, n, m, tot;
void init(){
for(int i = 1; i<= n; i++) fa[i] = i;
memset(dis, 0, sizeof(dis));
memset(up, 0, sizeof(up));
memset(Max, 0, sizeof(Max));
memset(edge, 0, sizeof(edge));
tot = 0;
}
int find(int x){
if(fa[x] == x) return x;
else return fa[x] = find(fa[x]);
}
void Union(int u, int v){
int fu = find(u), fv = find(v);
if(fu != fv) fa[fu] = fv;
}
void dfs(int u){
/*
for(int i = 1; i <= 20; i++){
up[u][i] = up[up[u][i - 1]][i - 1];
Max[u][i] = max(Max[u][i - 1], Max[up[u][i - 1]][i - 1]);
}
*/
for(int i = 0; i < edge[u].size(); i++){
int v = edge[u][i].first;
int len = edge[u][i].second;
if(dis[v] == 0){
dis[v] = dis[u] + 1;
Max[v][0] = len;
up[v][0] = u;
dfs(v);
}
}
}
void init_lca(){
for(int j = 1; (1 << j) <= n; j++){
for(int i = 1; i <= n; i++){
up[i][j] = up[up[i][j - 1]][j - 1];
Max[i][j] = max(Max[i][j - 1], Max[up[i][j - 1]][j - 1]);
}
}
}
int getans(int a, int b){
if(dis[a] < dis[b]) swap(a, b);
int c = dis[a] - dis[b], res = 0;
for(int i = 0; (1 << i) <= n; i++){
if(c & (1 << i)){
res = max(res, Max[a][i]);
a = up[a][i];
}
}
if(a == b) return res;
for(int i = 20; i >= 0; i--){
if(up[a][i] != up[b][i]){
res = max(res, Max[a][i]);
res = max(res, Max[b][i]);
a = up[a][i];
b = up[b][i];
}
}
return max(res, max(Max[a][0], Max[b][0]));
}
int main()
{
scanf("%d", &T);
while(T--){
scanf("%d %d", &n, &m);
init();
for(int i = 1; i <= m; i++){
int x, u, v;
scanf("%d %d %d", &x, &u, &v);
if(x == 1){
int fu = find(u), fv = find(v);
if(fu == fv) continue;
fa[fu] = fv;
edge[u].push_back(make_pair(v, i));
edge[v].push_back(make_pair(u, i));
}
else q[++tot].p = i, q[tot].u = u, q[tot].v = v;
}
for(int i = 1; i <= n; i++)
if(dis[i] == 0){
dis[i] = 1;
dfs(i);
}
init_lca();
for(int i = 1; i<= tot; i++){
int fu = find(q[i].u), fv = find(q[i].v);
if(fu != fv) printf("-1\n");
else {
int ans = getans(q[i].u, q[i].v);
if(ans > q[i].p) printf("-1\n");
else printf("%d\n", ans);
}
}
}
return 0;
}
在此輸入正文