zoj 3299(区间改动+离散化)
题意:有n个由小木块组成的长条木块要掉下来。给出木块的左右区间,然后有给了m个木板的左右区间和高度用来接住木块,由于木块是由小木块接触组成的,也就是木板能够接住一部分的木块。剩下的会继续掉落,问最后每一个木板上有多少个小木块。
题解:这道题用线段树可解,还有还有一个比較机智的做法。
先说线段树,左右区间到3×1e7,假设用线段树解决须要离散化。
把木板从低到高排序后用一个线段树flag维护每一个区间相应的木板编号。这样高的木板就能够覆盖低木板的编号,然后用还有一个线段树sum维护每一个长条木块在每一个区间内的数量。由于有可能n个长条木块区间有重叠。所以一个区间内不会仅仅有一排小木块,那么每更新一个长条木块,相应的区间的长条木块数量加1。
最后查询每一个区间全部的小木块数量就是相应的长条木块数量乘区间长度。一開始一直MLE,然后把离散用的map换成二分查找就水过去了。
下面是线段树做法的代码:
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 100001;
struct Board {
int l, r, h, id;
}boa[N];
int n, m, l[N], r[N];
long long res[N];
int sum[N << 4], flag[N << 4];
vector<int> a;
bool cmp(const Board& a, const Board& b) {
return a.h < b.h;
}
void pushdown(int k) {
if (flag[k]) {
flag[k * 2] = flag[k * 2 + 1] = flag[k];
flag[k] = 0;
}
if (sum[k]) {
sum[k * 2] += sum[k];
sum[k * 2 + 1] += sum[k];
sum[k] = 0;
}
}
void modify1(int k, int left, int right, int l1, int r1, int x) {
if (l1 <= left && right <= r1) {
flag[k] = x;
return;
}
pushdown(k);
int mid = (left + right) / 2;
if (l1 < mid)
modify1(k * 2, left, mid, l1, r1, x);
if (r1 > mid)
modify1(k * 2 + 1, mid, right, l1, r1, x);
}
void modify2(int k, int left, int right, int l1, int r1) {
if (l1 <= left && right <= r1) {
sum[k]++;
return;
}
pushdown(k);
int mid = (left + right) / 2;
if (l1 < mid)
modify2(k * 2, left, mid, l1, r1);
if (r1 > mid)
modify2(k * 2 + 1, mid, right, l1, r1);
}
void query(int k, int left, int right) {
if (flag[k]) {
res[flag[k]] += (long long)sum[k] * (a[right] - a[left]);
return;
}
if (left + 1 == right)
return;
pushdown(k);
int mid = (left + right) / 2;
query(k * 2, left, mid);
query(k * 2 + 1, mid, right);
}
int main() {
while (scanf("%d%d", &n, &m) == 2) {
a.clear();
memset(sum, 0, sizeof(sum));
memset(flag, 0, sizeof(flag));
memset(res, 0, sizeof(res));
for (int i = 1; i <= n; i++) {
scanf("%d%d", &l[i], &r[i]);
a.push_back(l[i]);
a.push_back(r[i]);
}
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &boa[i].l, &boa[i].r, &boa[i].h);
boa[i].id = i;
a.push_back(boa[i].l);
a.push_back(boa[i].r);
}
sort(a.begin(), a.end());
a.erase(unique(a.begin(), a.end()), a.end());
int cnt = a.size();
sort(boa + 1, boa + 1 + m, cmp);
for (int i = 1; i <= m; i++) {
int pos1 = lower_bound(a.begin(), a.end(), boa[i].l) - a.begin();
int pos2 = lower_bound(a.begin(), a.end(), boa[i].r) - a.begin();;
modify1(1, 0, cnt - 1, pos1, pos2, boa[i].id);
}
for (int i = 1; i <= n; i++) {
int pos1 = lower_bound(a.begin(), a.end(), l[i]) - a.begin();
int pos2 = lower_bound(a.begin(), a.end(), r[i]) - a.begin();;
modify2(1, 0, cnt - 1, pos1, pos2);
}
query(1, 0, cnt - 1);
for (int i = 1; i <= m; i++)
printf("%lld\n", res[i]);
printf("\n");
}
return 0;
}
还有一种做法是看别人的题解的,速度又快代码又短(就喜欢写代码短的╮(╯▽╰)╭),不须要离散化。把全部木块和木板所在区间从左到右扫描一边,结合绘图非常好理解。
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
const int N = 100005;
struct Board {
int h, l, r;
long long num;
}boa[N << 2];
struct Node {
int st, id, v;//区间起点。区分木块还是木板。区分左右端点
}node[N << 2];
int n, m;
map<int,int> mp;//存当前处理区间内全部的木板,左值是木板高度,右值是木板相应编号
bool cmp(const Node& a, const Node& b) {
if (a.st != b.st)
return a.st < b.st;
return a.v < b.v;
}
int main() {
while (scanf("%d%d", &n, &m) == 2) {
mp.clear();
int cnt = 0, l, r;
for (int i = 1; i <= n; i++) {
scanf("%d%d", &l, &r);
node[++cnt].st = l, node[cnt].id = 0, node[cnt].v = 1;
node[++cnt].st = r, node[cnt].id = 0, node[cnt].v = -1;
}
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &boa[i].l, &boa[i].r, &boa[i].h);
boa[i].num = 0;
node[++cnt].st = boa[i].l, node[cnt].id = i, node[cnt].v = 1;
node[++cnt].st = boa[i].r, node[cnt].id = i, node[cnt].v = -1;
}
sort(node + 1, node + 1 + cnt, cmp);
int pre = node[0].st, cnt1 = 0;//当前处理区间起点,当前区间的长条木块数量
for (int i = 1; i <= cnt; i++) {
if (mp.rbegin() != mp.rend()) {//map自己主动排序。所以map里最后一个值一定是最大的。也就是最高的木板
int id = mp.rbegin() -> second;//右值是编号
boa[id].num += (long long)(node[i].st - pre) * cnt1;//小木块数量是长条木块乘区间长度
}
if (!node[i].id) {//当前处理区间是长条木块
if (node[i].v == 1)
cnt1++;//长条木块数量加1
else
cnt1--;
}
else {//木板
if (node[i].v == 1)//左端点增加木板
mp[boa[node[i].id].h] = node[i].id;
else//右端点去掉木板
mp.erase(boa[node[i].id].h);
}
pre = node[i].st;//更新处理区间起点
}
for (int i = 1; i <= m; i++)
printf("%lld\n", boa[i].num);
printf("\n");
}
return 0;
}
zoj 3299(区间改动+离散化)的更多相关文章
- poj 2528(区间改动+离散化)
题意:有一个黑板上贴海报.给出每一个海报在黑板上的覆盖区间为l r,问最后多少个海报是可见的. 题解:由于l r取值到1e7,肯定是要离散化的,但普通的离散化会出问题.比方[1,10],[1,4],[ ...
- ZOJ 3299 线段树 离散化
本来是个很简单的题目,难住我的主要是这么几点 1.它所有的点都是坐标,不是实际的砖块,1,3指的是1-2 2-3的砖块...后来就是用1 代表1-2 ,2代表2-3.....,这样的话,每次读入的数据 ...
- hiho1079 线段树区间改动离散化
题目链接: hihocoder1079 代码: #include<iostream> #include<cstdio> #include<cstring> #inc ...
- POJ-2528 Mayor's posters (线段树区间更新+离散化)
题目分析:线段树区间更新+离散化 代码如下: # include<iostream> # include<cstdio> # include<queue> # in ...
- POJ 2528 Mayor's posters (线段树+区间覆盖+离散化)
题意: 一共有n张海报, 按次序贴在墙上, 后贴的海报可以覆盖先贴的海报, 问一共有多少种海报出现过. 题解: 因为长度最大可以达到1e7, 但是最多只有2e4的区间个数,并且最后只是统计能看见的不同 ...
- ZOJ 2301 Color the Ball 线段树(区间更新+离散化)
Color the Ball Time Limit: 2 Seconds Memory Limit: 65536 KB There are infinite balls in a line ...
- hiho一下21周 线段树的区间修改 离散化
离散化 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho在回国之后,重新过起了朝7晚5的学生生活,当然了,他们还是在一直学习着各种算法~ 这天小Hi和小Ho ...
- POJ 2528 Mayor's posters(线段树/区间更新 离散化)
题目链接: 传送门 Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Description The citizens of By ...
- POJ 2528 Mayor's posters(线段树区间染色+离散化或倒序更新)
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 59239 Accepted: 17157 ...
随机推荐
- Matlab 2018b 新特性
新特性简要介绍 一.实时编辑器 所创建的脚本不仅可以捕获代码,还可以讲述与人分享的故事.自动化的上下文提示可让您在编程时快速推进,并且将结果与可视化内容和您的代码一起显示. 二.App Designe ...
- Javascript:父类可以调用子类吗?
问:父类可以调用子类吗? 答:可以,经典的模板方法模式就是用的这个特性.
- Appium+python自动化20-查看iOS上app元素属性
前言 学UI自动化首先就是定位页面元素,玩过android版的appium小伙伴应该都知道,appium的windows版自带的Inspector可以定位app上的元素 Mac版的appium1.6的 ...
- OpenCV学习(7) 分水岭算法(1)
分水岭算法主要用于图像分段,通常是把一副彩色图像灰度化,然后再求梯度图,最后在梯度图的基础上进行分水岭算法,求得分段图像的边缘线. 下面左边的灰度图,可以描述为右边的地 ...
- 使用工具将安卓Android apk应用转换成Bar BlackBerry 10格式
首先要强调的是命令行工具使用起来虽然比较方便,但是对使用者有一定要求.而使用在线的网页进行转换虽然步骤比较多,但是操作比较简单.所以,对于初步接触的同学来讲,建议还是使用上一篇博文的在线转换工具比较好 ...
- Sqlite-SQLiteHelper类,操作SQLite数据库
using System; using System.Data; using System.Text.RegularExpressions; using System.Xml; using Syste ...
- C#控件一览表
C#控件一览表 .窗体 .常用属性 ()Name属性:用来获取或设置窗体的名称,在应用程序中可通过Name属性来引用窗体. () WindowState属性: 用来获取或设置窗体的窗口状态. 取值有三 ...
- 将应用发布到WasLiberty的两种方法
1.直接将War放到defaultserver(或其它自定义server)的dropin目录. 一放进去,war中的app就会随着server启动起来,这个war是会被解压的,用find / -nam ...
- 开源工作流CCBPM中关于解决谷歌等浏览器silverlight的问题
CCBPM的流程设计器和表单设计器.是通过silverlight实现的. 有些用户和学习者在安装完CCFlow,执行流程设计器时,常常会出现提示安装silverlight.明明已经安装了,为什么还会出 ...
- springmvc 入门(1)
1.1 Springmvc 本套课程基于spring4.X来讲解的 SpringMVC 概述 Spring 为展现层提供的基于 MVC 设计理念的优秀的 Web 框架,是目前最主流的 MVC 框架之一 ...