Bond(並查集-按秩合併)
阿新 • • 發佈:2019-01-24
題意:給出一張n個點m條邊的無向圖, 每條邊有一個危險度,有q個詢問, 每次給出兩個點s、t,找一條路, 使得路徑上的最大危險度最小。
思路:首先,我們可以發現,如果求一個最小生成樹, 那麼任意兩點, 在生成樹上有唯一路徑, 而且這條路徑上的最大危險值一定最小。 但是n和q都太大, 如果直接順著樹走,每次詢問最大複雜度O(n), 那麼複雜度高達O(n^2),會超時。 我們知道, 並查集在用了路徑壓縮之後效率高達O(n), 但是卻破壞了樹形結構, 所以不能用路徑壓縮。 然而我們經常忽視了按秩合併這個方法, 即使不用路徑壓縮, 僅僅靠按秩合併, 複雜度也可低至O(logn)。 因此我們只需按秩合併, 然後詢問的時候向根回溯就行了, 複雜度mlogn。
細節參見程式碼:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; typedef long long ll; const double PI = acos(-1.0); const double eps = 1e-6; const int mod = 1000000000 + 7; const int INF = 1000000000 + 7; const int maxn = 50000 + 10; int T,n,m,p[maxn],ra[maxn],edge[maxn],vis[maxn]; struct node { int a, b, c; bool operator < (const node& rhs) const { return c < rhs.c; } }a[100000 + 10]; int _find(int x) { return p[x] == x ? x : _find(p[x]); } void Union(int a, int b, int c) { int x = _find(a); int y = _find(b); if(x == y) return ; if(ra[x] < ra[y]) { p[x] = y; edge[x] = c; } else { p[y] = x; edge[y] = c; if(ra[x] == ra[y]) ra[x]++; } } void pre() { sort(a, a+m); for(int i=1;i<=n;i++) { p[i] = i; ra[i] = 0; vis[i] = -1; } for(int i=0;i<m;i++) { Union(a[i].a,a[i].b,a[i].c); } } int query(int x, int y) { int ans1 = 0, ans2 = -1; int cur = x; while(true) { vis[cur] = ans1; if(cur == p[cur]) break; ans1 = max(ans1, edge[cur]); cur = p[cur]; } cur = y; while(true) { if(vis[cur] >= 0) { ans2 = max(ans2, vis[cur]); break; } if(cur == p[cur]) break; ans2 = max(ans2, edge[cur]); cur = p[cur]; } cur = x; while(true) { vis[cur] = -1; if(cur == p[cur]) break; cur = p[cur]; } return ans2; } int u,v,q,kase=0; int main() { while(~scanf("%d%d",&n,&m)) { for(int i=0;i<m;i++) { scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c); } if(kase) printf("\n"); else ++kase; pre(); scanf("%d",&q); while(q--) { scanf("%d%d",&u,&v); printf("%d\n",query(u, v)); } } return 0; }