金牌導航 啟發式合併-連通性詢問 題解
阿新 • • 發佈:2022-04-02
題面:
注意本題強制線上
做法詳解:
一看到每一次加一條邊,詢問某兩個點的聯通的就自然而然地能想到使用並查集。
我們考慮最暴力的做法:
每一次從第一條邊開始依次加邊,直到某次加邊之後 \(u,v\) 聯通
顯然這樣做是不可以的,很明顯我們不可能每一次都從頭加一遍邊,所以就考慮這樣直接來一條邊加一條然後維護一個其他的資訊。
我們考慮並查集使用按秩合併,對於一個合併 \(y\) 合併到 \(x\) 裡,我們考慮維護一個數組 val[y] 代表直接合並 \(y\) 地這一個合併是第幾次合併,也就是第幾條加入的邊,因為我們的每一個點會且僅會被當作子樹直接合並一次,所以這個陣列的值也是確定的。這樣就考慮對於每一組詢問該如何去回答.
我們能發現一個很奇妙的性質,對於使 \(u,v\)
現在的問題就是如何去找它們在並查集上的唯一路徑,這個時候其實我們的按秩合併的作用就體現出來了,我們能發現按秩合併的並查集,**任何一條從根出發的鏈的長度都不會超過 \(log_{2}n\) **,所以我們可以直接從這兩個點暴力向上跳,然後將經過的邊取最大值就好了.暴力向上跳還是有一些細節的,具體見程式碼.
時間複雜度: \(O(mlog_{2}n)\)
AC程式碼:
#include<bits/stdc++.h> using namespace std; const long long MAXN = 1e6+5; long long tot,n,m,fa[MAXN],height[MAXN],val[MAXN],last_ans = 0; long long find_fa(long long x){ while(fa[x] != x) x = fa[x]; return x; } void merge(long long x,long long y,long long num){ x = find_fa(x), y = find_fa(y); //按秩合併 if(x == y) return; if(height[x] < height[y]) swap(x,y); fa[y] = x; val[y] = num; if(height[x] == height[y]) height[x]++; } long long get_ans(long long x,long long y){ long long fa_x = find_fa(x),fa_y = find_fa(y); if(fa_x != fa_y) return 0; else{ long long cnt_x = 0,cnt_y = 0,ans = 0; fa_x = x,fa_y = y; while(fa[fa_x]!=fa_x){ fa_x = fa[fa_x]; cnt_x++; } while(fa[fa_y]!=fa_y){ fa_y = fa[fa_y]; cnt_y++; } if(cnt_x < cnt_y){ swap(x,y); swap(cnt_x,cnt_y); } for(long long i=1; i<=cnt_x - cnt_y; i++){ //跳到同一深度 ans = max(ans,val[x]); x = fa[x]; } while(x != y){ //個人碼風習慣這裡寫 fa[x] != fa[y] ,然後下面統計一下 ans = max(val[x],val[y],ans) ,但是因為可能 x 或 y 就是根所以直接跳上面就會出大問題 ans = max(ans,val[x]); ans = max(ans,val[y]); x = fa[x];y = fa[y]; } return ans; } } int main(){ // freopen("in.txt","r",stdin); // freopen("out.txt","w",stdout); memset(val,0x3f,sizeof(val)); cin>>n>>m; for(long long i=1; i<=n; i++){ fa[i] = i; height[i] = 1; } for(long long i=1; i<=m; i++){ long long from,to,opt; cin>>opt>>from>>to; from^=last_ans;to^=last_ans; if(opt == 0){ merge(from,to,++tot); // printf("%d %d\n",from,to); } else if(opt == 1){ last_ans = get_ans(from,to); printf("%lld\n",last_ans); } } return 0; }