方块游戏
(cubes.pas/c/cpp)
【题目描述】
小A和小B在玩一个方块游戏。编号为1到n(1<=n<=30000)的n个方块正放在地上。每个构成一个立方柱。
游戏开始后,小A会给小B发出p(1<=p<=100000)个指令。
1、移动(M):将包含X的立方柱移动到包含Y的立方柱上。
2、统计(C):统计含X的立方柱中,在X下方的方块数目。
写个程序帮小B完成游戏。
【输入数据】
第1行输入P,之后P行每行输入一条指令。形式为“M X Y”或者“C X”。
输入保证不会有将立方柱放在自己头上的指令。
【输出数据】
每一行,对于每个统计指令,输出其结果。
【样例输入】
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
【样例输出】
1
0
2
【数据范围】
对于40%的数据,n,P≤200。
对于60%的数据,n,P≤2000。
对于100%的数据,n,P≤100000。
分析:
非常巧妙地并查集。
题目说的是将A放在B上,显然我们维护并查集时用路径压缩,那么要计算下方的个数,显然是做不到的,所以我们更换思路:
将B放在A上面,那么题意所指的A下方的方块其实就是我们更改题意后的A上方的方块数,路径压缩和合并的时维护一下就可以了。
参考程序:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=110000;
int f[maxn],ans[maxn],sum[maxn];
int find(int x){
if (f[x]==x)return x;
if (f[f[x]]==f[x])return f[x];
find(f[x]);ans[x]+=ans[f[x]];f[x]=f[f[x]];
return f[x];
}
void move(int u,int v){
int fu=find(u),fv=find(v);
ans[fu]+=sum[fv];f[fu]=fv;sum[fv]+=sum[fu];
}
int main(){
freopen("cubes.in","r",stdin);
freopen("cubes.out","w",stdout);
int T;
scanf("%d",&T);
for (int i=1;i<=T;i++)
f[i]=i,sum[i]=1,ans[i]=0;
while (T--){
char cmd;
scanf("\n%c",&cmd);
if (cmd=='M'){
int x,y;
scanf("%d%d",&x,&y);
move(x,y);
}else{
int x;
scanf("%d",&x);
find(x);
printf("%d\n",ans[x]);
}
}
return 0;
}