HDU 4391 - Paint The Wall - 分块哈希入门
题目链接 : 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 - 分块哈希入门的更多相关文章
- HDU 4391 Paint The Wall(分块+延迟标记)
Paint The Wall Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...
- HDU 4391 Paint The Wall(分块的区间维护)
题意:给出几个操作,把l-r赋值为z,询问l-r有几个z,其中z < INT_MAX 思路:因为z很大,所以很难直接用线段树去维护.这里可以使用分块来解决.我们可以让每个块用map去储存map[ ...
- HDU 4391 Paint The Wall 段树(水
意甲冠军: 特定n多头排列.m操作 以下是各点的颜色 以下m一种操纵: 1 l r col 染色 2 l r col 问间隔col色点 == 通的操作+区间内最大最小颜色数的优化,感觉非常不科学... ...
- hdu 1543 Paint the Wall
http://acm.hdu.edu.cn/showproblem.php?pid=1543 #include <cstdio> #include <cstring> #inc ...
- 线段树 扫描线 L - Atlantis HDU - 1542 M - City Horizon POJ - 3277 N - Paint the Wall HDU - 1543
学习博客推荐——线段树+扫描线(有关扫描线的理解) 我觉得要注意的几点 1 我的模板线段树的叶子节点存的都是 x[L]~x[L+1] 2 如果没有必要这个lazy 标志是可以不下传的 也就省了一个pu ...
- 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) ...
- hdu 3669 Cross the Wall(斜率优化DP)
题目连接:hdu 3669 Cross the Wall 题意: 现在有一面无限大的墙,现在有n个人,每个人都能看成一个矩形,宽是w,高是h,现在这n个人要通过这面墙,现在只能让你挖k个洞,每个洞不能 ...
- 【分段哈希】H. Paint the Wall
https://www.bnuoj.com/v3/contest_show.php?cid=9147#problem/H [题意] 在一个长为H,宽为W的白墙上选一个矩形区域涂颜色,后涂的颜色会覆盖先 ...
- HDU - 6394 Tree(树分块+倍增)
http://acm.hdu.edu.cn/showproblem.php?pid=6394 题意 给出一棵树,然后每个节点有一个权值,代表这个点可以往上面跳多远,问最少需要多少次可以跳出这颗树 分析 ...
随机推荐
- Java基础知识强化之IO流笔记21:FileInputStream读取数据
1. 字节输入流的操作步骤: (1)创建字节输入流的对象 (2)调用read()方法读取数据,并把数据显示到控制台 (3)关闭字节输入流的对象资源 2. FileInputStream构造: File ...
- H.264视频在android手机端的解码与播放(转)
随着无线网络和智能手机的发展,智能手机与人们日常生活联系越来越紧密,娱乐.商务应用.金融应用.交通出行各种功能的软件大批涌现,使得人们的生活丰富多彩.快捷便利,也让它成为人们生活中不可取代的一部分.其 ...
- IP 转地址
1.需要 QQWry.Dat IP 地址数据库 2辅助类库 using System; using System.Collections.Generic; using System.IO; usin ...
- ASPNET5 管理应用程序的状态
1. 应用程序状态选项 在ASP.NET5当中,全局的Application对象没有了,转而被In Memory Caching所代替,ASPNET5当中有下多种管理状态的方式: HttpContex ...
- myeclipse 'no default proposals' when use 'alt + /'.
solution: Window -> Preferences -> Java -> Editor -> Content Assist -> Advanced in th ...
- SQL 生成可配置流水号
需求背景每执行一次方法,根据公式返回最新的流水号.第一次使用时需要先插入一条数据,BizSeqValue 为流水起始号:A2014030000,Formula 为公式:A[yyyy][mm][c4], ...
- Spring和CXF整合时报Unsupported major.minor version 51.0异常
好吧,官网上有写:The current plan is that CXF 3.1 will no longer support Java 6 and will require Java 7 or n ...
- Oracle11G 数据库 expdp、impdp使用示例
expdp 备份数据库.expdp/impdp简单测试 操作系统层面创建目录 [root@Oracle11g ~]# mkdir -p /home/oracle/db_back/ 修改目录的所属用户. ...
- this、new、apply和call详解
讲解this指针的原理是个很复杂的问题,如果我们从javascript里this的实现机制来说明this,很多朋友可能会越来越糊涂,因此本篇打算换一个思路从应用的角度来讲解this指针,从这个角度理解 ...
- ubuntu下安装Vmare Workstation,并安装mac补丁
最近想学习一下关于ios方面的开发,但是苦于自己的电脑已经装了两个系统:一个win7,一个ubuntu.两系统均装在物理硬盘上,不想格盘,所以装个虚拟机玩玩.决定使用Vmare Workstation ...