题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=4391

题意 :

给一段区间, 有两种操作

1 : 给 x 到 y 的区间染色为 z

2 : 查询 x 到 y 的区间内颜色z的数目

思路 :

这题的z最大2^31-1, 区间长度最大1e5, 用线段树将颜色离散化之后维护也存不下

所以用分块哈希, 将一个长度为n的区间分为sqrt(n)块分块维护, 每一块中都用map记录某些颜色的个数

分块哈希 :

修改, 查询一段区间, 对于完整覆盖到的区间, 是可以很快进行修改和查询的

而不完整覆盖的区间至多只有两个, 可以暴力修改

创建一个结构体HashBlock, 其中记录本身长度, 覆盖情况flag, 初始化为-1(代表未被完整覆盖)

确定长度为n的区间, 每块长度为len, 故一共分成了 tot = (n - 1) / s + 1 块

特殊的是最后一段长度是 min(n, (tot) * len) - (tot-1) * len

修改一个区间l, r时, 令la = l / len, ra = r / len, 从[la+1, ra]都被完整覆盖可以直接更新

而区间 [l, (l / len + 1) * len] 和 [r * len, r] 这两段可能未被完整覆盖, 需要手动更新

我细节讲这么多就也为了提醒自己, 再细节的说不下去了, 请看代码吧

第一次写分块哈希的代码, 参考了CXlove, 感谢

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map> using namespace std; const int MAXN = 1e5+; struct HashBlock{
int sizee, color;
map<int, int> m;
} block[]; int c[MAXN];
int len;
int n; void Init()
{
len = (int)sqrt(n);
int tot = (n - ) / len + ;
for(int i = ; i < tot; i++) {
block[i].sizee = min(n, (i+) * len) - i * len;
block[i].color = -;
block[i].m.clear();
}
} //如果一个区间要手动更新, 需要将上一次整块更新的颜色先覆盖, 再重新手动更新
//与线段树中pushdown异曲同工
void PushDown(int step)
{
if(block[step].color != -) {
block[step].m.clear();
for(int i = step * len; i < n && i < (step+) * len; i++) {
c[i] = block[step].color;
block[step].m[c[i]]++;
}
block[step].color = -;
}
} void Update(int l, int r, int color)
{
int la = l / len, ra = r / len;
//完整覆盖的区间可直接更新
for(int i = la + ; i < ra; i++) {
block[i].color = color;
}
//暴力更新未被完整覆盖的部分
if(la != ra) {
PushDown(la), PushDown(ra);
for(int i = l; i < (la+) * len; i++) {
block[la].m[c[i]]--, block[la].m[color]++, c[i] = color;
}
for(int i = ra * len; i <= r; i++) {
block[ra].m[c[i]]--, block[ra].m[color]++, c[i] = color;
}
}
else { //是同一段区间
PushDown(la);
for(int i = l; i <=r; i++) {
block[la].m[c[i]]--, block[la].m[color]++, c[i] = color;
}
}
} int Query(int l, int r, int color)
{
int ans = ;
int la = l / len, ra = r / len;
for(int i = la + ; i < ra; i++) {
if(block[i].color == color) ans += block[i].sizee;
else if(block[i].color == - && \
block[i].m.find(color) != block[i].m.end()) {
ans += block[i].m[color];
}
}
if(la != ra) {
PushDown(la), PushDown(ra);
for(int i = l; i < (la+) * len; i++) {
ans += c[i] == color;
}
for(int i = ra * len; i <= r; i++) {
ans += c[i] == color;
}
}
else {
PushDown(la);
for(int i = l; i <=r ; i++) {
ans += c[i] == color;
}
} return ans;
} int main()
{
int q; while(scanf("%d %d", &n, &q) != EOF) {
Init();
for(int i = ; i < n; i++) {
scanf("%d", &c[i]);
block[i/len].m[c[i]]++;
}
while(q--) {
int cmd, l, r, z;
scanf("%d %d %d %d", &cmd, &l, &r, &z);
if(cmd == ) Update(l, r, z);
else printf("%d\n", Query(l, r, z));
}
} return ;
}

HDU 4391 - Paint The Wall - 分块哈希入门的更多相关文章

  1. HDU 4391 Paint The Wall(分块+延迟标记)

    Paint The Wall Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  2. HDU 4391 Paint The Wall(分块的区间维护)

    题意:给出几个操作,把l-r赋值为z,询问l-r有几个z,其中z < INT_MAX 思路:因为z很大,所以很难直接用线段树去维护.这里可以使用分块来解决.我们可以让每个块用map去储存map[ ...

  3. HDU 4391 Paint The Wall 段树(水

    意甲冠军: 特定n多头排列.m操作 以下是各点的颜色 以下m一种操纵: 1 l r col 染色 2 l r col 问间隔col色点 == 通的操作+区间内最大最小颜色数的优化,感觉非常不科学... ...

  4. hdu 1543 Paint the Wall

    http://acm.hdu.edu.cn/showproblem.php?pid=1543 #include <cstdio> #include <cstring> #inc ...

  5. 线段树 扫描线 L - Atlantis HDU - 1542 M - City Horizon POJ - 3277 N - Paint the Wall HDU - 1543

    学习博客推荐——线段树+扫描线(有关扫描线的理解) 我觉得要注意的几点 1 我的模板线段树的叶子节点存的都是 x[L]~x[L+1] 2 如果没有必要这个lazy 标志是可以不下传的 也就省了一个pu ...

  6. HDU 4012 Paint on a Wall(状压+bfs)

    Paint on a Wall Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others) ...

  7. hdu 3669 Cross the Wall(斜率优化DP)

    题目连接:hdu 3669 Cross the Wall 题意: 现在有一面无限大的墙,现在有n个人,每个人都能看成一个矩形,宽是w,高是h,现在这n个人要通过这面墙,现在只能让你挖k个洞,每个洞不能 ...

  8. 【分段哈希】H. Paint the Wall

    https://www.bnuoj.com/v3/contest_show.php?cid=9147#problem/H [题意] 在一个长为H,宽为W的白墙上选一个矩形区域涂颜色,后涂的颜色会覆盖先 ...

  9. HDU - 6394 Tree(树分块+倍增)

    http://acm.hdu.edu.cn/showproblem.php?pid=6394 题意 给出一棵树,然后每个节点有一个权值,代表这个点可以往上面跳多远,问最少需要多少次可以跳出这颗树 分析 ...

随机推荐

  1. Centos6.3 配置yum 163源

    1. 下载repo文件    下载地址:http://mirrors.163.com/.help/CentOS6-Base-163.repo 2. 备份并替换系统的repo文件[root@localh ...

  2. Python Socket通信原理

    [Python之旅]第五篇(一):Python Socket通信原理   python Socket 通信理论 socket例子 摘要:  只要和网络服务涉及的,就离不开Socket以及Socket编 ...

  3. MySQL存储过程的基本函数(三)

    (1).字符串类 首先定义一个字符串变量:set @str="lxl"; CHARSET(str) //返回字串字符集 select charset(@str);+-------- ...

  4. 下拉框上移、下移、添加、移除demo

    <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <sc ...

  5. eclipse - 自动换行

    eclipse自动换行,设置的感觉不是很好用,可以从这个网址进行更新安装: http://ahtik.com/eclipse-update/

  6. iOS开发知识点:理解assign,copy,retain变strong

    一..h和.m文件的变化说明 1.对于.h头文件,主要是将属性定义由retain变为strong @property (retain, nonatomic) 变为 @property (strong, ...

  7. Linux网络配置命令ifconfig输出信息解析

    eth0      Link encap:Ethernet  HWaddr 00:1e:4f:e9:c2:84 inet addr:128.224.163.153  Bcast:128.224.163 ...

  8. Hive学习之二 《Hive的安装之自定义mysql数据库》

    由于MySQL便于管理,在学习过程中,我选择MySQL. 一,配置元数据库. 1.安装MySQL,采用yum方式. ①yum  install  mysql-server,安装mysql服务端,安装服 ...

  9. css3之box-sizing

    css盒子模型中包括几种重要的属性,包括margin.border.padding以及content.但浏览器对其盒子模型的解释则有所不痛,启用标准模式还是IE(怪)模式是与当前页面的文档声明相关的. ...

  10. 利用C++ RAII技术自动回收堆内存

    在C++的编程过程中,我们经常需要申请一块动态内存,然后当用完以后将其释放.通常而言,我们的代码是这样的: 1: void func() 2: { 3: //allocate a dynamic me ...