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 题意 给出一棵树,然后每个节点有一个权值,代表这个点可以往上面跳多远,问最少需要多少次可以跳出这颗树 分析 ...
随机推荐
- HDU 5120 Intersection(几何模板题)
题意:给定两个圆环,求两个圆环相交的面积. 思路:由于圆心和半径不一样,分了好多种情况,后来发现只要把两个圆相交的函数写好之后就不需要那么复杂了.两个圆相交的面积的模板如下: double area_ ...
- C#—委托分析
1.简单委托示例 using System; using System.Collections.Generic; using System.Linq; using System.Text; names ...
- 用js生成下载文件
function downloadFile(fileName, content) { var aLink = document.createElement('a'); var blob = new B ...
- ExecuteScalar 要求已打开且可用的 Connection。连接的当前状态为已关闭。
本人遇到的一个小问题,希望能帮助大家 出现这个问题就是在此操作之前已经被的程序关闭了连接,比如在执行这块代码之前不幸执行了存储过程..,就会导致这个问题发生
- Ext4.1 tree grid的右键菜单
Ext4.1 tree grid的右键菜单功能其实挺简单的 只要添加一个itemcontextmenu事件,并在事件中显示出Menu就OK了. 代码: this.tree.on('itemcontex ...
- iOS开发网络资源整理-持续更新
本文记录iOS开发相关的网络社区和博客 1.objc中国 网址:http://objccn.io 简介:onevcat创建,项目的成立源于国内 Objective-C 社区对 objc.io 的翻译活 ...
- angular自定义指令详解
指令(directive)是angular里面最核心也是最难懂的东西,在慕课网看了下大漠穷秋老湿的视频,自己百度半天做了一些小test,总算把一切都搞明白了. 先列出学习来源: 指令中controll ...
- MESH
本文由博主(YinaPan)原创,转载请注明出处:http://www.cnblogs.com/YinaPan/p/Unity_meshtest.html A class that allows c ...
- (转)C++静态库与动态库
本文出自 http://www.cnblogs.com/skynet/p/3372855.html 吴秦 什么是库 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不 ...
- C++函数覆盖的思考
最近碰到一些问题,一开始很难调试和解决,最后发现原来是在基类函数的模板方法中对子类需要重写的函数没有使用virtual,如下 class Base { public: void say(){test( ...