題目:Building Blockphp
連接:http://acm.hdu.edu.cn/showproblem.php?pid=2818數組
題意:ui
有 n 個元素,初始分紅 n 堆(每堆一個),接下來有 p 個操做:spa
1. M x y :將 下標爲x 的元素所在的堆 放在 y元素所在堆的上面code
2. C x :問 下標爲x 的元素下方有多少元素。
blog
思路:遞歸
並查集的好題!!!get
普通並查集通常是問集合內的元素個數,這題問的是集合內指定元素下方的元素個數。io
這裏,我用了三個數組,fa[],son[],unum[],fa[x]表示x上方的元素,son[x]表示x下方的元素,unum[x]表示x下面的元素個數(包括x元素不包括son[x]下方的元素)。class
假設我如今要將L堆放在R堆上面,那麼son[C]就變成了D了,也就是L堆的最底層孩子的son值改成R堆祖先下標。這裏的改變不必更改各元素的unum屬性,而在查詢下方元素個數時,遞歸的同時要主意路徑壓縮。
AC代碼:
1 #include<stdio.h> 2 #include<queue> 3 using namespace std; 4 #define N 30005 5 6 int fa[N], son[N], unum[N]; 7 8 int find(int x) 9 { 10 return fa[x]= fa[x]==x ? x : find(fa[x]); 11 } 12 13 pair<int, int> findSon(int x) 14 { 15 if(son[x]==x) return make_pair(x, unum[x]); 16 17 pair<int, int> ret = findSon(son[x]); 18 int child = ret.first; 19 int num = ret.second; 20 21 unum[x] = unum[x] + num - unum[child]; 22 son[x] = child; 23 24 return make_pair(child, unum[x] + unum[child]); 25 } 26 27 void mov(int x, int y) 28 { 29 int fx = find(x); 30 int fy = find(y); 31 if(fx==fy) return ; 32 else fa[fy]=fx; 33 34 int sx = findSon(x).first; 35 son[sx] = fy; 36 } 37 38 int main() 39 { 40 int m, x, y; 41 while(scanf("%d", &m)!=EOF) 42 { 43 for(int i=0; i<N; i++) fa[i]=i, son[i]=i, unum[i]=1; 44 while(m--) 45 { 46 char s[2]; 47 scanf("%s", s); 48 if(s[0]=='M') 49 { 50 scanf("%d%d", &x, &y); 51 mov(x, y); 52 } 53 else 54 { 55 scanf("%d", &x); 56 printf("%d\n", findSon(x).second-1); 57 } 58 } 59 } 60 return 0; 61 }