搭积木 并查集

现在有一排n(n<=300000)个积木,按顺序从1到n编号,我们想把这些积木堆起来。

刚开始的时候,n个积木每一个是单独的柱子,接下来我们会进行m次操作,把这些积木堆成更高的柱子。

有两种操作类型:

1.将x好积木所在的柱子按照原顺序堆到y号积木所在的柱子上面

2.计算x号积木所在的柱子当中,堆在x积木之下的积木个数

Input

第一行一个正整数m,不会给出n的值

接下来m行,每行描述一个操作,如果这一行以M开头,那么接下来两个正整数x,y表示进行一次操作1;如果以C开头,接下来一个正整数x,表示进行一次操作2。

Output

输出若干行,表示每一次操作2的答案

Constraints

对于40%的数据 m<200

对于100%的数据 m<100000

一眼看出并查集(不解释)

洛谷有一道很相似的题目:银河英雄传说

我们每次进行操作1,将x与y所在的并查集合并

操作2输出x下的积木个数

在这中间进行一些处理就好了(好像什么也没说)

在上课没时间好好写注释了(っ•?ω•?)っ??? 我爱学习

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=30010;
int pre[maxn];
int m;
int deep[maxn];
int under[maxn];
int findpa(int a)
{
    if(pre[a]==a) return a;
    int fa=findpa(pre[a]);
    under[a]+=under[pre[a]];
    return pre[a]=fa;
}
void step1(int x,int y){
    int xx=findpa(x);
    int yy=findpa(y);
    if(xx==yy) return;
    under[xx]+=deep[yy];
    deep[yy]+=deep[xx];
    deep[xx]=0;
    pre[xx]=yy;
    return;
}
void step2(int x)
{
    int xx=findpa(x);
    cout<<under[x]<<endl;
}

void read(){
    for(int i=1;i<=maxn;i++) pre[i]=i,under[i]=0,deep[i]=1;
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        int x,y;
        char c;
        cin>>c;
        if(c==‘M‘) {cin>>x>>y;step1(x,y);}
        if(c==‘C‘) {cin>>x;step2(x);}
    }
}
int main(){
    //freopen("cubes.in","r",stdin);
    //freopen("cubes.out","w",stdout);
    read();
    return 0;
}

原文地址:https://www.cnblogs.com/cheng-qing/p/9734723.html

时间: 2024-11-02 21:18:42

搭积木 并查集的相关文章

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

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

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

【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],则下方的积木

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

并查集(个人模版)

并查集: 1 int find(int a) 2 { 3 int r=a; 4 while(f[r]!=r) 5 r=f[r]; 6 int i=a; 7 int j; 8 while(i!=r) 9 { 10 j=f[i]; 11 f[i]=r; 12 i=j; 13 } 14 return r; 15 } 16 int merge(int a,int b) 17 { 18 int A,B; 19 A=find(a); 20 B=find(b); 21 if(A!=B) 22 { 23 f[B

并查集应用

题目描述: One way that the police finds the head of a gang is to check people's phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls

【bzoj3674】 可持久化并查集加强版

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 (题目链接) 题意 维护并查集3个操作:合并:回到完成第k个操作后的状态:查询. Solution 其实就是用主席树的叶子节点维护并查集的可持久化数组fa[]. 细节 终于认识到了按秩合并的强大,单纯写个路径压缩Re飞,写了路径压缩+按秩合并比单纯的按秩合并每快多少→_→ 代码 // bzoj3674 #include<algorithm> #include<iostream>

BZOJ1015[JSOI2008]星球大战starwar[并查集]

1015: [JSOI2008]星球大战starwar Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 5253  Solved: 2395[Submit][Status][Discuss] Description 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重