1. 程式人生 > >GYM - 100814 C.Connecting Graph

GYM - 100814 C.Connecting Graph

暴力 display 分享圖片 新的 每次 opened tin 圖片 def

題意:

  初始有n個點,m次操作。每次操作加一條邊或者詢問兩個點第一次連通的時刻(若不連通輸出-1)。

題解:

  用並查集維護每個點所在連通塊的根。對於每次加邊,暴力的更新新的根。

  每次將2個塊合並時,將小的塊並向大的塊。這麽合並使得每個點的根最多更新log2n次,並儲存每次更新信息(更新時刻以及新的根)。

  對於每一次詢問,二分兩個點第一次連通的時刻。對於每一個二分的時刻,求的是兩點的根是否相同。

  由於存儲過了每個點根的更新信息,所以再用二分求出他這個時刻的根。

技術分享圖片
#include <bits/stdc++.h>
using namespace std;
typedef 
long long ll; const int N = 1e5+10; int t; int n, m; int u, v, k; int f[N], num[N]; vector<pair<int, int> > g[N]; vector<int> c[N]; bool check(int x) { int l = 0, r = g[u].size()-1; while(l <= r) { int mid = l+r>>1; if(g[u][mid].first <= x) l = mid+1
; else r = mid-1; } int p1 = g[u][r].second; l = 0, r = g[v].size()-1; while(l <= r) { int mid = l+r>>1; if(g[v][mid].first <= x) l = mid+1; else r = mid-1; } int p2 = g[v][r].second; if(p1==p2) return 1; return 0; } int main() { scanf(
"%d", &t); while(t--) { scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { num[i] = 1; f[i] = i; c[i].clear(); g[i].clear(); c[i].push_back(i); g[i].push_back(make_pair(0, i)); } for(int i = 1; i <= m; i++) { scanf("%d%d%d", &k, &u, &v); if(k&1) { u = f[u]; v = f[v]; if(u!=v) { if(num[u]>num[v]) swap(u, v); for(int j = 0; j < num[u]; j++) { c[v].push_back(c[u][j]); f[c[u][j]] = v; g[c[u][j]].push_back(make_pair(i, v)); } num[v] += num[u]; num[u] = 0; c[u].clear(); } } else { int l = 0, r = i-1; while(l<=r) { int mid = l+r>>1; if(check(mid)) r = mid-1; else l = mid+1; } if(check(r+1)) printf("%d\n", r+1); else puts("-1"); } } } }
View Code

GYM - 100814 C.Connecting Graph