2020牛客暑期多校第八場I-Interesting Computer Game(離散化+並查集)
阿新 • • 發佈:2020-08-04
CSDN食用連結:https://blog.csdn.net/qq_43906000/article/details/107797019
題目大意:給你T組資料,每組資料給你n對數,分別表示為\(a_i,b_i(1\leq a_i,b_i\leq 10^9)\),你每次都可以取其中的一個,但如果之前\(a_i\)已經被取過了,就不能再取了,\(b_i\)也是一樣的。那麼問你總共可以取多少種不同的數。\((T\leq 10,n\leq 1e5)\)
輸入
2
6
1 2
2 3
3 4
1 4
1 3
2 4
5
1 2
1 2
1 3
2 3
5 6
輸出
Case #1: 4
Case #2: 4
emmm,開局就跑了波網路流。。。T了,後面nb隊友過的。事實上我們可以將這些關係畫出來,我們會發現,對於一個關係組,如果裡面有環的話那麼能夠取得的數字就是整個圖的大小,否則的話就只能取其大小-1個。至於判斷有環無環,我們直接判斷每次出現的兩個數字是否有共同的祖先就可以了,然後我們可以傳遞這種關係。不過由於\(a_i,b_i\)
以下是AC程式碼:
#include <bits/stdc++.h> using namespace std; const int mac=1e5+10; const int inf=1e9+10; int au[mac],av[mac]; int num[mac<<1],father[mac<<1],bk[mac<<1]; int sz[mac<<1],lu[mac],lv[mac]; int find(int x){return x==father[x]?x:father[x]=find(father[x]);} int main() { int t; scanf ("%d",&t); for (int cse=1; cse<=t; ++cse){ int n,cnt=0; scanf ("%d",&n); for (int i=1; i<=n; i++){ scanf ("%d%d",&au[i],&av[i]); num[++cnt]=au[i],num[++cnt]=av[i]; } sort(num+1,num+1+cnt); int it=unique(num+1,num+1+cnt)-num; for (int i=1; i<=n; i++){ lu[i]=lower_bound(num+1,num+it,au[i])-num; lv[i]=lower_bound(num+1,num+it,av[i])-num; } int ans=0; for (int i=1; i<it; i++) father[i]=i,bk[i]=0,sz[i]=1; for (int i=1; i<=n; i++){ int u=lu[i],v=lv[i]; int fu=find(u),fv=find(v); if (fu!=fv){ father[fu]=fv; sz[fv]+=sz[fu]; bk[fv]=max(bk[fv],bk[fu]); } else { bk[fv]=1; } } for (int i=1; i<it; i++){ if (father[i]!=i) continue; ans+=sz[i]-1; if (bk[i]) ans++; } printf ("Case #%d: %d\n",cse,ans); } return 0; }