【lazy标记得思想】HDU3635 详细学习并查集
部分内容摘自以下大佬的博客,感谢他们!
http://blog.csdn.net/dm_vincent/article/details/7769159
http://blog.csdn.net/dm_vincent/article/details/7655764
基础得可以去看上面的连接,再此我只记录一些温故而知新得知识点
并查集,连通起来后类似一颗颗得树,我们得基本操作是Find函数,寻找树根,所以树得高度,成为了,并查集算法快不快的关键条件,为了加快算法,我们采取以下操作:
1.尽可能得让每一个结点直接连到树根(过程中优化)
int Find(int x)
{
while(x != pre[x])
{
pre[x] = pre[pre[x]];
x = pre[x];
}
return x;
}
2.进行树得合并得时候,避免造成畸形数目
void join(int a,int b)
{
int u = Find(a);
int v = Find(b);
if(u != v)
{
if(s[u] > s[v])
{
pre[v] = u;
s[u] += s[v];
}
else
{
pre[u] = v;
s[v] += s[u];
}
}
}
这里用到了s数组记录的是这个树得大小,一开始初始化都为1,更新只需要再连树得时候进行
我觉得以下这个理解或者应用,让我更加理解了并查集得数据结构,以及解决问题时得建模思考方向
对这个问题抽象之后,就是要求进行若干次union操作之后,还会剩下多少颗树(或者说还剩下多少Connected Components)。反映到这个例子中,就是要求有多少“圈子”。其实,这也是社交网络中的最基本的功能,每次系统向你推荐的那些好友一般而言,会跟你在一个“圈子”里面,换言之,也就是你可能认识的人,以并查集的视角来看这层关系,就是你们挂在同一颗树上。
题目大意:
题意:起初球i是被放在i号城市的,在年代更迭,世事变迁的情况下,球被转移了,而且转移的时候,连带该城市的所有球都被移动了:T A B(A球所在的城市的所有球都被移动到了B球所在的城市),Q A(问:A球在那城市?A球所在城市有多少个球呢?A球被转移了多少次呢?)
(上面题意的描述摘自:http://www.cnblogs.com/Shirlies/archive/2012/03/06/2382118.html)
不错得一道题目,按照我们原来的并查集优化来想,前两个输出都比较简单,就是次数问题
(ps:当然了,根据题意,我们时不能进行平衡树得保持得,因为最终状态(树根)是确定得)
对于次数:第一个跟新得地方肯定是join函数里面,比较容易想到的时一旦合并,就使每一个合并的元素++,这样的话会超时,只能优化,有点类似线段树中得lazy标记,我们不能一更到底,那就先更新最上层,然后想办法传递给下层,如和传递呢,好像我们还有Find函数
在Find函数中,我们会进行路径压缩,这很好,因为保证了,tm【x】相加得唯一性,这时候要稍微改变以下Find函数,因为我要传递得值以前是根,现在不是了所以我要后退一步,就是从判断x是不是根后退到判断pre【x】是不是根,然后进行tm【x】得更新优化,一旦优化完毕我们就进行路径压缩,防止合并多次。虽然有了路径压缩,但是最后我们还是要进行一次Find(a),才能进行后续得输出。
不错的一道题目,
#include <iostream>
#include <string.h>
#include <cstdio>
using namespace std;
const int maxn = 1e6+1e3;
int pre[maxn];
int s[maxn];
int tm[maxn]; int Find(int x)
{
//路径压缩
while(pre[x] != pre[pre[x]])
{
tm[x] += tm[pre[x]];
pre[x] = pre[pre[x]];//路径压缩!!非常棒!!!
}
return pre[x];
}
void join(int a,int b)
{
int u = Find(a);
int v = Find(b);
if(u != v)
{
pre[u] = v;
tm[u]++;
s[v] += s[u];
}
}
void init(int n)
{
for(int i = 0;i <= n;i++)
{
pre[i] = i;
s[i] = 1;
tm[i] = 0;
}
}
int main()
{
char c;
int t,a,b,n,m;
scanf("%d",&t);getchar();
int cas = 1;
while(t--)
{
scanf("%d %d",&n,&m);getchar();
init(n);
printf("Case %d:\n",cas++);
while(m--)
{
scanf("%c",&c);
if(c == 'T')
{
scanf("%d %d",&a,&b);getchar();
join(a,b);
}
else
{
scanf("%d",&a);getchar();
int ans = Find(a);
printf("%d %d %d\n",ans,s[ans],tm[a]);
printf("%d && \n",pre[a]);
}
}
}
return 0;
}
【lazy标记得思想】HDU3635 详细学习并查集的更多相关文章
- Dragon Balls(hdu3635带权并查集)
题意:n个城市有n个龙珠,T a,b 代表将龙珠a移动到b城市,Q a代表查询龙珠a所在城市,该城市有多少颗龙珠,该龙珠移动了多少次. 注意:移动时是将龙珠所在该城市所有龙珠都移动,每个龙珠不会再回 ...
- 算法学习 并查集(Union-Find) (转)
并查集是我暑假从高手那里学到的一招,觉得真是太精妙的设计了.以前我无法解决的一类问题竟然可以用如此简单高效的方法搞定.不分享出来真是对不起party了.(party:我靠,关我嘛事啊?我跟你很熟么?) ...
- HDU 1698 Just a Hook (线段树 成段更新 lazy-tag思想)
题目链接 题意: n个挂钩,q次询问,每个挂钩可能的值为1 2 3, 初始值为1,每次询问 把从x到Y区间内的值改变为z.求最后的总的值. 分析:用val记录这一个区间的值,val == -1表示这 ...
- 浅谈算法——线段树之Lazy标记
一.前言 前面我们已经知道线段树能够进行单点修改和区间查询操作(基本线段树).那么如果需要修改的是一个区间该怎么办呢?如果是暴力修改到叶子节点,复杂度即为\(O(nlog n)\),显然是十分不优秀的 ...
- Hbase技术详细学习笔记
注:转自 Hbase技术详细学习笔记 最近在逐步跟进Hbase的相关工作,由于之前对Hbase并不怎么了解,因此系统地学习了下Hbase,为了加深对Hbase的理解,对相关知识点做了笔记,并在组内进行 ...
- 万字长文,以代码的思想去详细讲解yolov3算法的实现原理和训练过程,Visdrone数据集实战训练
以代码的思想去详细讲解yolov3算法的实现原理和训练过程,并教使用visdrone2019数据集和自己制作数据集两种方式去训练自己的pytorch搭建的yolov3模型,吐血整理万字长文,纯属干货 ...
- Redis初识、设计思想与一些学习资源推荐
一.Redis简介 1.什么是Redis Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.从2010 年 ...
- HDU 3911 Black And White (线段树区间合并 + lazy标记)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3911 给你n个数0和1,m个操作: 0操作 输出l到r之间最长的连续1的个数 1操作 将l到r之间 ...
- POJ 3237 Tree (树链剖分 路径剖分 线段树的lazy标记)
题目链接:http://poj.org/problem?id=3237 一棵有边权的树,有3种操作. 树链剖分+线段树lazy标记.lazy为0表示没更新区间或者区间更新了2的倍数次,1表示为更新,每 ...
随机推荐
- one by one 项目 part 6
package Controllerservlet; import java.io.IOException; import java.io.PrintWriter; import java.util. ...
- SpringDataJPA模糊查询遇到的坑
遇到的情况:在做短信渠道管理添加时,先要去校验数据库中是否有该产线-短信类型-渠道的记录,如果存在就不添加. //在库中是否存在该记录 private boolean ifExistChannelCo ...
- bootstrap中给表格设置display之后表格宽度变小问题解决
问题描述:bootstrap中给表格设置display之后表格宽度变小了 解决方案:给表格加上 display:table样式就可以了.
- afinal框架下 ViewInject的使用
1.可以在BaseActivity界面onCreate 方法setContentView后加上该语句. initInjectedView(this); 2.@ViewInject(id=R.id.v_ ...
- Android模拟器内安装应用
一.通过apk安装器安装应用 1.下载apk安装器(网上随便搜一个就可以) 2.下载要测试的应用的apk,我这里下载的是微信的apk 3.打开apk安装器,点击右上角的Devices选择要安装到的设备 ...
- SVN服务器端的安装和配置
第2章 SVN 的下载与安装 服务器端的安装和配置 所有的开发人员用自己的账号登录进来就可以拥有对仓库里面的所有文件的读和写的权限 创建用户
- C# .net MD5加密函数
using System.Web.Security; string password =FormsAuthentication.HashPasswordForStoringInConfigFile(t ...
- .net VS2008 时间加减,时间段,时间格式化到秒
举个例子: DateTime time1 = DateTime.Now; DateTime time2 = time1.AddDays(1); time1是当前时间,time2比当前时间多一天.也就是 ...
- 利用redis完成自动补全搜索功能(二)
前面介绍了自动完成的大致思路,现在把搜索次数的功能也结合上去.我采用的是hash表来做的,当然也可以在生成分词的时候,另外一个有序集合来维护排序, 然后2个有序集合取交集即可.这里介绍hash的方式来 ...
- 通过yiic来创建yii应用
一.通过yiic来创建yii应用 (*yiic命令在yii下载包的framework目录下) 1.把你自已的php环境添加到系统环境变量中. 2.在命令行下输入: yiic webapp 位置\名称 ...