POJ 1988 Cube stacking【并查集高级应用+妙用deep数组】
Description
moves and counts.
* In a move operation, Farmer John asks Bessie to move the stack containing cube X on top of the stack containing cube Y.
* In a count operation, Farmer John asks Bessie to count the number of cubes on the stack with cube X that are under the cube X and report that value.
Write a program that can verify the results of the game.
Input
* Lines 2..P+1: Each of these lines describes a legal operation. Line 2 describes the first operation, etc. Each line begins with a 'M' for a move operation or a 'C' for a count operation. For move operations, the line also contains two integers: X and Y.For count operations, the line also contains a single integer: X.
Note that the value for N does not appear in the input file. No move operation will request a move a stack onto itself.
Output
Sample Input
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
Sample Output
1
0
2
题意:搬箱子和架箱子,如果箱子上面有箱子,则再不打乱顺序的条件下把整体搬过去
先普及下基础:并查集就是在路径压缩的条件下找根,每次在函数返回的时候,顺带把路上遇到的人的BOSS改为最后找到的祖宗编号。这样可以提高今后找到最高领导人(也就是树的祖先)的速度。然后再merge中判断是不是在一个连通分量,若不是,则连通,把一个连通图的根赋给另一个连通图,靠这样的方式去合并一个连通分量。
看了网上大牛的思路做出来的,在并查集的基础上加一个deep数组,用来存旧根的深度,旧根的深度等于新根上一次的节点数,这里就是一个线树,最后输出的时候,查根,减去改节点的深度,再减去本身,就得到下面的箱子,很巧妙啊,整体分为了根的节点数,本身,本身的深度三部分,思路实在巧妙。
如 给出这个数据:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=;
int fa[maxn],son[maxn],deep[maxn]; void init()
{
for(int i=;i<maxn;i++)
{
fa[i]=i;
son[i]=;
deep[i]=;
}
}
int find(int x)
{
if(x==fa[x]) return x; int tmp=fa[x];
fa[x]=find(tmp);
deep[x]+=deep[tmp];//fantasty return fa[x];
} void join(int a,int b)//amazing
{
int rt1=find(a);
int rt2=find(b);
if(rt1 != rt2)
{
fa[rt2]=rt1;
deep[rt2]=son[rt1];
son[rt1]+=son[rt2];
}
} int main()
{
int p;
char op[];
int a,b;
int q; scanf("%d",&p);
init();
for(int i=;i<p;i++)
{
scanf("%s",op);
if(op[]=='M')
{
scanf("%d%d",&a,&b);
join(a,b);
}
else
{
scanf("%d",&q);
printf("%d\n",son[find(q)]-deep[q]-);
}
}
} /* 题意: 说是有n块砖,编号从1到n,有两种操作,第一是把含有x编号的那一堆砖放到含有编号y的那一堆砖的上面,
第二是查询编号为x的砖的下面有多少块砖。用count[x]表示下面有多少块砖。 现在需要把两堆砖合并,显然要用上并查集,可是普通的合并之后如何知道x的下面有多少块砖呢,
思考合并的过程,对于一堆砖,移动到另一堆砖上时,上面那一堆上每块砖的count[i]应该加上下面一堆砖的数量,
这个操作对于上面一堆砖的根来说是简单的,我使用uset[i]表示连通分量,舒适化时所有的uset[i]为-1,负数代表这个节点为根,
1代表这个连通分量的节点总数为1,以样例为例,首先将1放到6上面,即将6合并到1所在的连通分量中,合并的过程中我们知道两个信息,
第一是当前连通分量6->1的节点数量为2,6距离1的距离为1,同理,将2放到4上面,这个连通分量节点个数为2,,4到2的距离为1
最后,我们将包含6的这个连通分量合并到包含2的这个连通分量中,
此时连通分量数为4,曾经的6->1连通分量的根距离合并后的连通分量的根的距离为2,就是4->2的连通分量的节点数 说了半天有什么用处呢,经过上面这个过程,
我们知道了每一个节点到它第一次被合并时的那个根节点的距离,6->1的距离为1,1到4的距离为2,2到4的距离为1,
这样我们在查询4的下面有多少块砖时,直接用4(连通分量节点数)-(1+2)(6到根节点的距离)-1=2 **************************************************** 不用说肯定用并查集,貌似就是不进行路径压缩的无脑模拟?不对,500000个操作,30000艘船,不超时才怪!
那怎么办呢?一路径压缩战舰顺序就被改变,怎么才能在路径压缩的同时随时得知同一舰队中两艘战舰的位置?
输入是合并与询问两艘战舰之间的“距离”,遇到问题是路径压缩后“距离”(间隔战舰数量)变了,不压缩太慢了,那我们不就可以再开一个数组,存下需要的“距离”了吗?这个数组存的距离就是在路径压缩时变化了的那个:第i艘到第fa[i]艘之间的战舰数量,数组名就命名成front吧,因为路径压缩全部完成,即同一舰队中所有元素的fa[i]都等于这个舰队第一艘战舰时,front[i]=第i艘战舰前方有多少战舰(这么搞就像前缀和,路径压缩时可以一层一层地边压缩边修正下去)。 易知在还未进行路径压缩时对于同一舰队非第一艘战舰,front[i]=1,第一艘战舰front[i]=0(一个舰队的第一艘,不是编号为一的那艘),路径压缩首先不断向fa[i]走fa[i]=find(fa[i]),走到队首,fa[i]==i,front[i]=0不变,返回队首的编号,回溯至递归上一层,把队首的编号那么第二艘的front增加0就是1,为何是增加呢?因为前面说过完成路径压缩即find函数跑完后front[i]的值就是编号i的战舰前方有几艘战舰,路径压缩前则是到fa[i]的距离,一路径压缩,就相当于fa[i]直接越过front[fa[i]]艘战舰,从i的前一艘指向队首,fa[i]前进那么多,front[i]自然也要增加那么多,修改之后继续回溯,同理第三层front[i]+=front[fa[i]]……路径压缩完成。 合并时怎么办呢,定义合并函数uni(x,y)表示将x所在那列移到y所在那列后面(千万别搞反了),那么我们就要先找到两列的队首(依然用x、y存),像普通并查集那样fa[x]=y,然后维护front数组,这时遇到问题啦——front[y]要加多少呢?显然是x那列的战舰数,难道还要循环一遍统计一下吗?那太慢了,存下来吧,于是num[i]表示编号i这列的战舰总数(i是队首,不然每合并一次要修改的太多了,查询时num[i]时先find(i)找到队首吧),front[y]+=num[x],num[x]+=num[y],合并完成。 还有一个问题就是询问。对于一组询问ask(x,y),先找到他们的队首fx=find(x);fy=find(y);(顺便把路径压缩进行完全了,不用担心front[i]被重复增加了,路径压缩完全时front[fa[i]]==0,因为fa[i]就是队首呀),然后判断fx!=fy就输出-1,否则就输出abs(front[x]-front[y])-1(到队首的距离之差减一就是他们间隔距离)。 */
路径压缩-节点到根节点的距离题目
POJ 1988 Cube stacking【并查集高级应用+妙用deep数组】的更多相关文章
- poj.1988.Cube Stacking(并查集)
Cube Stacking Time Limit:2000MS Memory Limit:30000KB 64bit IO Format:%I64d & %I64u Submi ...
- POJ 1988 Cube Stacking(并查集+路径压缩)
题目链接:id=1988">POJ 1988 Cube Stacking 并查集的题目 [题目大意] 有n个元素,開始每一个元素自己 一栈.有两种操作,将含有元素x的栈放在含有y的栈的 ...
- POJ 1988 Cube Stacking( 带权并查集 )*
POJ 1988 Cube Stacking( 带权并查集 ) 非常棒的一道题!借鉴"找回失去的"博客 链接:传送门 题意: P次查询,每次查询有两种: M x y 将包含x的集合 ...
- [POJ 1988] Cube Stacking (带值的并查集)
题目链接:http://poj.org/problem?id=1988 题目大意:给你N个方块,编号从1到N,有两种操作,第一种是M(x,y),意思是将x所在的堆放到y所在的堆上面. 第二种是C(x) ...
- POJ 1988 Cube Stacking(带权并查集)
Cube Stacking Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 23678 Accepted: 8299 Ca ...
- POJ 1988 Cube Stacking 【带权并查集】
<题目链接> 题目大意: 有几个stack,初始里面有一个cube.支持两种操作: 1.move x y: 将x所在的stack移动到y所在stack的顶部. 2.count x:数在x所 ...
- POJ 1988 Cube Stacking(带权并查集)
哈哈,一次AC. 题意:给你 1-n 编号的立方体,然后移动包含指定编号的立方体的堆移到另一个堆上边, 询问指定的编号立方体下面有多少个立方体. 思路:由于并查集是存储的是它的父亲,那么只能从父亲那里 ...
- POJ 1988 Cube Stacking (种类并查集)
题目地址:POJ 1988 这道题的查找合并的方法都能想的到,就是一点没想到,我一直天真的以为查询的时候,输入后能立即输出,这种话在合并的时候就要所有的结点值都要算出来,可是经过路径压缩之后,没办法所 ...
- POJ1988(Cube Stacking)--并查集
题目链接:http://poj.org/problem?id=1988 题意:有n个元素,开始每个元素各自在一个栈中,有两种操作,将含有元素x的栈放在含有y的栈的顶端,合并为一个栈. 第二种操作是询问 ...
随机推荐
- [洛谷P2711]小行星
题目大意:有$n$颗行星,每颗行星的位置是$(x,y,z)$.每次可以消除一个面(即$x,y$或$z$坐标相等)的行星,求消除这些行星的最少次数. 题解:最小割,对于每一颗小行星,从 x 面的出点向 ...
- jocky1.0.3 (原joc) java混淆器 去除jdk版本限制
昨晚下班回去,研究了下jocky1.0.3的使用,发现编译时提示引用类库版本不对,捣弄了半个小时后终于理解,原来是我的jdk1.7版本过高,这货是06年的版本,到现在都没更新过,支持(限制)的最高版本 ...
- MySQL里执行SHOW INDEX结果中Cardinality的含义
今天在写一个Perl脚本,想自动化查找出MySQL数据库中可能无效的索引,于是根据朝阳的书上提到的一些规则,我来设计了一些判断方法,其中发现某个我想要的值就是SHOW INDEX FROM table ...
- 自定义toolbar教程
1.写toolbar的布局文件 ,toolbar.xml <?xml version="1.0" encoding="utf-8"?> <Re ...
- Ubuntu系统iptables规则的查看和清除
系统不支持service iptables restart,service iptables status,如何查看与清除iptable的规则呢? 一 iptables查看基本语法 iptables ...
- PHP报错Cannot adopt OID in UCD-SNMP-MIB、 LM-SENSORS-MIB
Cannot adopt OID in UCD-SNMP-MIB: Cannot adopt OID in LM-SENSORS-MIB: lmTempSensorsValue 运行PHP遇到这些错误 ...
- Linux基础(1)
一.Linux的安装及相关配置 1.VMware Workstation安装CentOS7.0 图文版 详细步骤可以看连接:http://blog.csdn.net/alex_my/article/d ...
- 【洛谷 P1337】[JSOI2004]平衡点 / 吊打XXX (模拟退火)
题目链接 正解就算了吧,谁叫我理生化 语数外 政史地都菜呢 模拟退火真玄学,不知道发生了什么就跑出答案了,原理就算了吧,能用(pianfen)就好. 当重物平衡时,势能一定是最小的,于是当我随机出一个 ...
- 愚蠢的LCAAAAA~~~~(>_<)~~~~
很愤怒!特别愤怒!超级愤怒!!! 我LCA居然错了!!而且是那种特别愚蠢的错误 我把代码都交错了!!! silasila 话不多说,代码上特别详细了 #include<bits/stdc++.h ...
- [bzoj1977][BeiJing2010组队]次小生成树 Tree——树上倍增+lca
Brief Description 求一个无向图的严格次小生成树. Algorithm Design 考察最小生成树的生成过程.对于一个非树边而言,如果我们使用这一条非树边去替换原MST的路径上的最大 ...