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=0,f=1; register char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;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=1;i<=30000;i++) fa[i]=top[i]=i; for(int i=1;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]]+1; top[y]=top[x]; } else{ x=read();find(x); printf("%d\n",cnt[x]); } } return 0; }
时间: 2024-10-20 22:24:29