Farmer John and Betsy are playing a game with N (1 <= N <= 30,000)identical cubes labeled 1 through N. They start with N stacks, each containing a single cube. Farmer John asks Betsy to perform P (1<= P <= 100,000) operation. There are two types of operations:
moves and counts.
* In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
* In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.
Write a program that can verify the results of the game.
moves and counts.
* In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
* In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.
Write a program that can verify the results of the game.
Input
* Line 1: A single integer, P
* Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.
Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.
* Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.
Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.
Output
Print the output from each of the count operations in the same order as the input file.
Sample Input
6 M 1 6 C 1 M 2 4 M 2 6 C 3 C 4
Sample Output
1 0 2
思路:第一次遇见带权并查集问题,,看了好久才晃晃呼呼的明白一丢丢
#include<iostream> #include<cstdio> #include<cstring> #include<iostream> using namespace std; const int N=1E5+7; const int nn=30000+10; int son[N];//表示当前树的大小 int father[N]; int dis[N];//表示到根结点的距离 int find(int x){ if(father[x]==x) return x; else { int k=father[x]; father[x]=find(father[x]); dis[x]+=dis[k];//这里主要就是起传递作用,因为我们在join函数中对根节点动了手脚,所以我可以采取这样的方式让所有节点都和根节点做同样的变化 return father[x]; } } void join(int x,int y){ int fx=find(x),fy=find(y); if(fx!=fy){ father[fy]=fx; dis[fy]=son[fx];//指的是根结点fy到总根节点fx的距离等于fx树的大小 son[fx]+=son[fy];//因为又来了几个新元素,,所以更新一下树的大小 } } void inint(){ memset(dis,0,sizeof(dis)); for(int i=1;i<nn;i++){ father[i]=i; son[i]=1; } } int main(){ int n; inint(); scanf("%d",&n); while(n--){ char s[10]; scanf("%s",s); if(s[0]=='M'){ int x,y; scanf("%d%d",&x,&y); join(x,y); } else { int z; scanf("%d",&z); printf("%d\n",son[find(z)]-dis[z]-1);//find(z)是根节点。son[find(z)]是树的总长度,dis[z]是Z到根节点的距离,相减后就是Z到末尾的个数,在减去-1,就是减去z } } return 0; }
上边的是固定最小的点,然后对跟不断改变根节点,我们还可以固定根节点,然后逐渐往树上加值:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; typedef long long ll; const int N= 1e5+7; const int nn=30000+10; ll fa[N];//父节点 ll dis[N];//表示到树根的距离 ll son[N];//表示这棵树的大小 ll find(int x){ if(x==fa[x]) return fa[x]; else { int k=fa[x]; fa[x]=find(k); dis[x]+=dis[k];//儿子节点==原儿子节点+父亲节点 return fa[x]; } } void join(int x,int y){ ll fx=find(x),fy=find(y); if(fx!=fy){ fa[fx]=fy;//这里我们让fy做根节点 dis[fx]=son[fy];//fx到根节点的距离等于当前树的大小 son[fy]+=son[fx];// 跟新树的大小 } } void inint(){ memset(dis,0,sizeof(dis)); for(int i=1;i<nn;i++){ son[i]=1; fa[i]=i; } } int main(){ int n; inint(); scanf("%d",&n); while(n--){ char s[10]; scanf("%s",s); if(s[0]=='M'){ int x,y; scanf("%d%d",&x,&y); join(x,y); } else { int z; scanf("%d",&z); find(z);//这一步是不可少的,因为我们要让每一个点都直接连接跟节点,但给出的z的父节点有可能不是根节点,所以要更新一下 // printf("%d\n",son[find(z)]-dis[z]-1); printf("%lld\n",dis[z]);//dis保存的就是到根的距离 } } return 0; }