约翰和贝西在叠积木。共有30000块积木,编号为1到30000。一开始,这些积木放在地上,自然地分成N堆。贝西接受约翰的指示,把一些积木叠在另一些积木的上面。一旦两块积木相叠, 彼此就再也不会分开了,所以最后叠在一起的积木会越来越高。约翰让贝西依次执行P条操作,操作分为两种:
第一种是移动操作,格式为“移动X到Y的上面”。X和Y代表两块积木的编号,意思是将X所的那堆积木,整体叠放到Y所在的那堆积木之上;
第二种是统计操作,格式为“统计Z下方的积木数量”。Z代表一块积木的编号,意思是贝西需要报告在编号为Z的积木之下还有多少块积木
请编写一个程序,帮助贝西回答每条统计问题。
输入输出格式
输入格式:
第一行:单个整数:P,1 ≤ P ≤ 10^5
第二行到第P + 1行:每行描述一条命令,如果这行开头的字母是 M,代表一条移动命令,后面的两个整数代表上文中的X和Y;如果开头字母是 C,代表一条统计命令。后面的整数代表上文中的Z,保证所有的移动命令都有意义,X和Y不会已经出现在同一堆积木里
输出格式:
对每一个统计命令,输出正确回答,用换行符分开每个查询的结果
输入输出样例
输入样例#1: 复制
6 M 1 6 C 1 M 2 4 M 2 6 C 3 C 4
输出样例#1: 复制
View Code
1 0 2
和银河英雄传几乎一模一样
唯一有区别的是 输出的是一个点前面的数量 一定要find一次更新一下!!!!
其他的带权并查集即可
更新的操作在find1里面要记得!!
#include<bits/stdc++.h> using namespace std; //input by bxd #define rep(i,a,b) for(int i=(a);i<=(b);i++) #define repp(i,a,b) for(int i=(a);i>=(b);--i) #define RI(n) scanf("%d",&(n)) #define RII(n,m) scanf("%d%d",&n,&m) #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k) #define RS(s) scanf("%s",s); #define ll long long #define REP(i,N) for(int i=0;i<(N);i++) #define CLR(A,v) memset(A,v,sizeof A) ////////////////////////////////// #define inf 0x3f3f3f3f const int N=1e6; int f[N],cnt[N],d[N],a,b; char s[3]; int find1(int x) { if(x==f[x])return x; int k=find1(f[x]); d[x]+=d[f[x]]; return f[x]=k; } void union1(int a,int b)//a放到b后面 { int x=find1(a),y=find1(b); d[x]+=cnt[y]; f[x]=y; cnt[y]+=cnt[x]; cnt[x]=0; } int main() { int n;RI(n); rep(i,1,30000+5)f[i]=i,cnt[i]=1,d[i]=0; rep(i,1,n) { RS(s); if(s[0]=='M') { RII(a,b); union1(a,b); } else { RI(a); int k=find1(a);//这条其实很关键 cout<<d[a]<<endl; } } return 0; }