1. 程式人生 > 實用技巧 >CF1380E.Merging Towers(並查集)

CF1380E.Merging Towers(並查集)

/*
 *1380E.Merging Towers
 *給出半徑為1~n的n個盤子和m個塔,要求每個塔上盤子的半徑始終從底向上遞減
 *一次操作可以將一個塔上的任意個盤子移動到另一個塔的頂部。
 *令某一情形下的複雜度為將所有盤子移動到同一個塔上所需的最小運算元。
 *題目給出m-1次詢問,每次詢問時輸出當前情形的複雜度併合併到兩個塔的盤子到同一個塔上
 *考慮如果一個一個搬碟子,答案是n-1。
 *如果有兩個相鄰的碟子,就把他們看成一個整體,答案可以減去1.
 *按照每堆的堆頂建樹,每次合併的時候,對於小樹的節點我們都判斷它在原陣列的相鄰節點的祖先節點是不是合併的大樹top點
 *如果是,既然相鄰那麼他們的半徑就是差值最小的,也就是說可以把他們看成一個整體 
  
*/ #include<bits/stdc++.h> using namespace std; const int maxn=2e5+100; vector<int> g[maxn]; int father[maxn]; int a[maxn]; int findfather (int x) { int a=x; while (x!=father[x]) x=father[x]; while (a!=father[a]) { int z=a; a=father[a]; father[z]=x; }
return x; } int main () { int n,m; scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); g[a[i]].push_back(i); } int wjm=n; for (int i=1;i<=m;i++) father[i]=i; for (int i=2;i<=n;i++) if (a[i-1]==a[i]) wjm--; printf("%d\n
",wjm-1); for (int i=1;i<m;i++) { int x,y; scanf("%d%d",&x,&y); int faX=findfather(x); int faY=findfather(y); if (g[faX].size()>g[faY].size()) swap(faX,faY); for (int j:g[faX]) { if (j+1<=n&&a[j+1]==faY) wjm--; if (j-1>=1&&a[j-1]==faY) wjm--; g[faY].push_back(j); } for (int j:g[faX]) a[j]=faY; father[faX]=faY; printf("%d\n",wjm-1); } }