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的栈的顶端,合并为一个栈. 第二种操作是询问 ...
随机推荐
- CSS继承—深入剖析
CSS的继承是指被包在内部的标签将拥有外部标签的样式性质.继承特性最典型的应用通常发挥在整个网页的样式预设,即整体布局声明.而需要要指定为其它样式的部份设定在个别元素里即可达到效果.这项特性可以给网页 ...
- line-height用法总结
Line-height是前端用语,经常被前端开发人员经常使用. line-height设置1.5和150%有什么区别?这是一个比较常见的前端面试题. 定义: line-height指的是文本行基线间的 ...
- Codeforces Round #392 (div.2) E:Broken Tree
orz一开始想不画图做这个题(然后脑袋就炸了,思维能力有待提高) 我的做法是动态规划+贪心+构造 首先把题目给的树变成一个可行的情况,同时weight最小 这个可以通过动态规划解决 dp[x]表示以x ...
- Spring AOP前置通知实例讲解与AOP详细解析
一.引出问题 有个接口TestServiceInter,有两个实现方法TestService和Test2Service.他们都有sayHello():我们的需求是在调用这两个方法之前,要先完成写日志的 ...
- 第116讲 boost::algorithm::string之替换和删除
http://www.360doc.com/content/16/0523/18/29304643_561672752.shtml
- arraylist和array的不同之处
https://www.cnblogs.com/wangbin2188/p/6524200.html
- java,jenkins
以前玩的是hudson ,现在玩的是jenkins.以前用的是Tomcat,现在不知道他们怎么不用... 1,装个Jenkins镜像. 2.配置项目: 先取个名字:exchange 配个svn: 构建 ...
- Ubuntu1604 install netease-cloud music
Two issue: 1. There is no voice on my computer, and the system was mute and cannot unmute. eric@E641 ...
- DIV的变高与变宽
代码: <!DOCTYPE HTML><html><head> <meta charset="utf-8"> <title&g ...
- CodeMirror编辑器文本框Textarea代码高亮插件,CodeMirror的简单实用例子
CodeMirror是一个用于编辑器文本框textarea代码高亮javascript插件,为各种编程语言实现关键字,函数,变量等代码高亮显示,丰富的api和可扩展功能以及多个主题样式,能满足您各种项 ...