[luoguP2342] 叠积木(并查集)

传送门

up[i] 表示一个木块上面有多少个

all[i] 表示整个连通块内有多少个

那么 一个木块下面的木块个数为 all[root[i]] - up[i] - 1

注意:up[i] 可以在 find 函数中维护,而 all[i] 不好维护,那么我们只需要祖先节点的 all[i] 表示整个连通块内木块的数目即可

   合并时也注意维护

——代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #define N 1000001
 4
 5 int n;
 6 int f[N], up[N], all[N];
 7
 8 inline int read()
 9 {
10     int x = 0, f = 1;
11     char ch = getchar();
12     for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1;
13     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘;
14     return x * f;
15 }
16
17 inline int find(int x)
18 {
19     if(x ^ f[x])
20     {
21         int fx = f[x];
22         f[x] = find(f[x]);
23         up[x] += up[fx];
24     }
25     return f[x];
26 }
27
28 int main()
29 {
30     int i, x, y, fx, fy;
31     char s[1];
32     n = read();
33     for(i = 1; i <= n; i++) f[i] = i, all[i] = 1;
34     for(i = 1; i <= n; i++)
35     {
36         scanf("%s", s);
37         if(s[0] == ‘M‘)
38         {
39             x = read();
40             y = read();
41             fx = find(x);
42             fy = find(y);
43             f[fy] = fx;
44             up[fy] += all[fx];
45             all[fx] += all[fy];
46         }
47         else
48         {
49             x = read();
50             fx = find(x);
51             printf("%d\n", all[fx] - up[x] - 1);
52         }
53     }
54     return 0;
55 }

时间: 2024-10-12 09:01:54

[luoguP2342] 叠积木(并查集)的相关文章

搭积木 并查集

现在有一排n(n<=300000)个积木,按顺序从1到n编号,我们想把这些积木堆起来. 刚开始的时候,n个积木每一个是单独的柱子,接下来我们会进行m次操作,把这些积木堆成更高的柱子. 有两种操作类型: 1.将x好积木所在的柱子按照原顺序堆到y号积木所在的柱子上面 2.计算x号积木所在的柱子当中,堆在x积木之下的积木个数 Input 第一行一个正整数m,不会给出n的值 接下来m行,每行描述一个操作,如果这一行以M开头,那么接下来两个正整数x,y表示进行一次操作1:如果以C开头,接下来一个正整数x,

洛谷OJ P1196 银河英雄传说(带权并查集)

题目描述 公元五八○一年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦 创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争.泰山压 顶集团派宇宙舰队司令莱因哈特率领十万余艘战舰出征,气吞山河集团点名将杨 威利组织麾下三万艘战舰迎敌. 杨威利擅长排兵布阵,巧妙运用各种战术屡次以少胜多,难免恣生骄气.在 这次决战中,他将巴米利恩星域战场划分成30000列,每列依次编号为1, 2, …, 30000.之后,他把自己的战舰也依次编号

【bzoj3376-方块游戏】带权并查集

题意: n块积木,m个操作或询问.每次移动积木的时候,约翰会选择两块积木X,Y,把X搬到Y的上方.如果X已经和其它积木叠在一起了,那么应将这叠积木整体移动到Y的上方:如果Y已经和其它积木叠在一起了的,假设在Y上方最高处的积木为Z,那么应将X所在的那叠积木移动到Z的上方.每次询问当前时刻,某一块积木的下方有多少块积木.n,m<=10^5 题解: 带权并查集.对于每个点x,维护当前所在并查集(也就是这一堆积木中)最下方的积木d[x],最上方的积木fa[x],x到最上方积木的距离f[x],则下方的积木

P2342 叠积木

P2342 叠积木 17通过 66提交 题目提供者wwqk4444 标签树状数组线段树USACO 难度普及+/提高 提交该题 讨论 题解 记录 最新讨论 暂时没有讨论 题目背景 Cube Stacking, 2004 Open 题目描述 约翰和贝西在叠积木.共有30000块积木,编号为1到30000.一开始,这些积木放在 地上,自然地分成N堆.贝西接受约翰的指示,把一些积木叠在另一些积木的上面.一旦两 块积木相叠, 彼此就再也不会分开了,所以最后叠在一起的积木会越来越高.约翰让贝西依 次执行P条

并查集 POJ 1988 Cube Stacking

题目传送门:    -------->这里<---------- 题目大意: 有标记1-N的方块,初始时一个砖块是一堆.然后进行以下操作 M X Y : 将 X 砖块所在堆 叠到 Y 砖块所在堆上面: C X :数在 X 砖块所在堆中 叠在X砖块下的砖块个数: 1<=N<=30000; 思路: 并查集,每一个砖块堆是一个集合.将每一堆的最上面一块砖设为根,合并时更新 Y 堆的根的 father 和 val (在Y上面的方块数) . 要达到这些目的,需要一个all数组,来记录每一堆里

hdu 2818 Building Block【基础带权并查集】

Building Block Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3365    Accepted Submission(s): 1009 Problem Description John are playing with blocks. There are N blocks (1 <= N <= 30000) numbe

带权并查集 POJ1988 POJ2492

单纯的并查集很简单,带权并查集还能解决更多的问题,才更好玩,来个题热身.对于下面的知识,现在就当你已经熟练掌握了递归和并查集的路径压缩. POJ1988:题目链接 http://poj.org/problem?id=1988 题目大意:有N(N<=30,000)堆方块,开始每堆都是一个方块.方块编号1 – N. 有两种操作:  M x y : 表示把方块x所在的堆,拿起来叠放到y所在的堆上.  C x : 问方块x下面有多少个方块. 操作最多有 P (P<=100,000)次.对每次C操作

hdu 2818 Building Block(带权并查集)

题目: 链接:点击打开链接 题意: 有N个积木,1到N编号.进行一些操作P次,M:X Y把X积木放到Y的上面,如果X和Y相等请忽略.C:X 计算X积木下的积木数目. 思路: 带权并查集的题目,定义数组sum[i]表示i积木下面积木的数目.遇到操作M,就把X和Y合并到同一个集合中.我们视每个结点为1个 Pile,其中rank[i]就表示每个Pile处的积木的个数,Initially, there are N piles, and each pile contains one block.所以,ra

CodeForces 745C Hongcow Builds A Nation 并查集

题意: 给了你n个城市 m条边 k个政府 每个政府管辖的区域内不能和其他政府的区域有相连 即政府之间不存在路径 问你在维护这种关系的同时 最多再加多少条边 思路: 先找出来每个联通块 再找出来没有归属的孤立的点 把他们都放到最大的联通块里 然后每个联通块之间的点两两连边是n*(n-1)/2条边 最后算出来的ans-m就好了 (看别人的博客学了一个max_element 1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a