P2342 叠积木

时间:2023-03-09 07:06:06
P2342 叠积木

P2342 叠积木

    • 17通过
    • 66提交
  • 题目提供者wwqk4444
  • 标签树状数组线段树USACO
  • 难度普及+/提高

提交该题 讨论 题解 记录

最新讨论

  • 暂时没有讨论

题目背景

Cube Stacking, 2004 Open

题目描述

约翰和贝西在叠积木。共有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:
1
0
2

说明

第一次查询时, 1 下面只有一个 6;第二次

查询时, 3 下面没有任何积木;第三次查询时,

4 下面有两块积木:1 和 6

AC代码+题解:

/*
题解:
正确性解释:以底层元素为并查集的代表元素,保证cnt[]更新到底端的时候不会多加,因为cnt[fa[x]]必为0
fa[x]=y; 表示x的父亲是y; (初始化是自身)
top[x]=t;表示x上面的代表编号是t; (初始化是自身)
cnt[x]=t;表示x以下木块的数量是t; (初始化是0)
find()更新时,两堆合并时,利用回溯,更新top[x]=top[t];cnt[x]=cnt[t]+cnt[x];(画图易知)
ps:每次合并或查询,都要find()一次,要不然会WA。
*/
#include<cstdio>
#include<iostream>
using namespace std;
#define N 30010
int fa[N],cnt[N],top[N];
inline int read(){
register int x=,f=;
register char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline char in(){
for(register char ch=getchar();;ch=getchar()) if(ch>='A'&&ch<='Z') return ch;
}
int find(int x){
if(fa[x]==x)return x;
int t=fa[x];
fa[x]=find(fa[x]);
fa[x]=fa[t];
top[x]=top[t];
cnt[x]=cnt[t]+cnt[x];
return fa[x];
}
int main(){
int n,x,y,a,b;char ch;
n=read();
for(int i=;i<=;i++) fa[i]=top[i]=i;
for(int i=;i<=n;i++){
if((ch=in())=='M'){
a=read();b=read();
x=find(a),y=find(b);
fa[x]=y;find(top[y]);
cnt[x]=cnt[top[y]]+;
top[y]=top[x];
}
else{
x=read();find(x);
printf("%d\n",cnt[x]);
}
}
return ;
}