poj-2528线段树练习
title: poj-2528线段树练习
date: 2018-10-13 13:45:09
tags:
- acm
- 刷题
categories: - ACM-线段树
概述
到现在也只是理解了kaungbin的代码,,,知道每一步做什么,,,但感觉就是哪里有些不对劲的样子,,,,
这道题有两个点是我感觉很重要的,,,一个是数据的离散化,,,另一个是线段树的变形,,,也就是它所维护的东西和之前见过的不一样了,,,,
分析思路
题意是这样的,,,在一个很大的区间里,,,不停的给每一个区间覆盖海报,,,每个覆盖的海报是不一样的,,然后问你最后一共有几个海报是露出来的,,,
大体上的思路是与所给贴海报相反的顺序贴海报,,,这样的话第一张(也就是原来顺序的最后一张)一定是全露出来的,,然后第二张(也就是原来顺序的倒数第二张)如果是在第一张的区间里说明它就被完全覆盖了,,如果是在第一张以外的其他地方,,,就说明这张也一定是露出来的,,,以此类推,,对于每一次判断出是露出来的++ans,,,最终全处理了就得到了答案,,,数据要离散后再用,,,
可以看出这样的写法中线段树只是用来判断每一次的贴海报,,,也就是说,,,线段树只是用来维护每一个区间是否被覆盖(更新),,,同时返回所要覆盖的区间是否有露出来的(查询),,,所以更新和查询的操作可以合并在一起,,,,
实现
数据的离散化
先说一下离散怎么实现:
首先原数据保存到x[maxn]数组,,,
然后把所有的数据复制到另一个数组a[maxn],,,
对其排序,,,
去重,,,
然后对去重的数组a[maxn]遍历进行离散,,,
这样想要知道知道原来数据中x所对应离散后的位置就为hash[x],,,
sort(a , a + count);
count = unique(a , a + count) - a;
for(int i = 0; i < count; ++i)
hash[a[i]] = i;
最后的代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
const int maxn = 1e5 + 10;
struct node
{
int l;
int r;
bool cov; //表示这个节点所代表的区间是否被覆盖
}node[maxn << 2];
struct poster //表示海报的结构体
{
int l;
int r;
}poster[maxn << 2];
void build(int rt , int l , int r)
{
node[rt].l = l;
node[rt].r = r;
node[rt].cov = false; //每一个区间初始化为未覆盖
if(l == r) return;
int mid = (l + r) >> 1;
build(lson);
build(rson);
}
bool post(int rt , int l , int r)
{
//当前节点,所要覆盖的额区间[l , r]
if(node[rt].cov) return false; //若这个区间已经被覆盖直接返回
if(node[rt].l == l && node[rt].r == r)
{
node[rt].cov = true; //未覆盖的前提下找到整个区间时
return true;
}
bool res;
int mid = (node[rt].l + node[rt].r) >> 1;
if(r <= mid) res = post(rt << 1 , l , r);
else if(l > mid)res = post(rt << 1 | 1 , l , r);
else
{
bool r1 = post(rt << 1 , l , mid);
bool r2 = post(rt << 1 | 1 , mid + 1 , r);
res = r1 || r2; //当跨两个区间时,,,要分别判断是否都是被覆盖的,,有一个没覆盖即露出就说明这个区间有露出的
}
if(node[rt << 1].cov && node[rt << 1 | 1].cov) //两个子区间都露出父节点也是露出
node[rt].cov = true;
return res;
}
int a[maxn];
int hash[10000010];
int main()
{
int T;scanf("%d" , &T);
while(T--)
{
int n;
scanf("%d" , &n);
int count = 0;
for(int i = 0; i < n; ++i)
{
scanf("%d%d" , &poster[i].l , &poster[i].r);
a[count++] = poster[i].l;
a[count++] = poster[i].r;
//相邻存点
}
//离散
sort(a , a + count);
count = unique(a , a + count) - a;
for(int i = 0; i < count; ++i)
hash[a[i]] = i;
build(1 , 0 , count - 1);
int ans = 0;
for(int i = n - 1; i >= 0; --i) //反着遍历,,有露出的就增一
if(post(1 , hash[poster[i].l] , hash[poster[i].r]))
++ans;
printf("%d\n" , ans);
}
}
//一个缺点,,,这样单纯的离散数据会出错,,,像这一组,,,
//但是poj上没有考虑这种情况,,,,应该是标程的离散也是这样把,,,,,,
//3
//1 10
//1 3
//6 10
//2
//应该是3
总结
暑假时接触过一次数据的离散化,,,但是当时只是会用就行,,,最终还是忘记了,,,只知道这样一个名词,,,这次花了点时间记忆了一下,,,但是还是没有仔细深入的看看,,,因为以前看到的离散化时用的lower_bound(),,,,而且操作更加的复杂,,,过一段时间再看看把,,,,
看到网上好多人用的线段树的结构和之前写的那样一样,,,build(),update(),query(),,,但就是理解不了,,,QAQ,,,看了kuangbin的写法反到理解了,,,虽然基本是照搬过来的,,,,再过几天要重写一遍,,,
(end)
poj-2528线段树练习的更多相关文章
- poj 2528(线段树+离散化) 市长的海报
http://poj.org/problem?id=2528 题目大意是市长竞选要贴海报,给出墙的长度和依次张贴的海报的长度区间(参考题目给的图),问最后你能看见的海报有几张 就是有的先贴的海报可能会 ...
- poj 2528 线段树区间修改+离散化
Mayor's posters POJ 2528 传送门 线段树区间修改加离散化 #include <cstdio> #include <iostream> #include ...
- poj 2528 线段树+离散化
题意:在墙上贴一堆海报(只看横坐标,可以抽象成一线段),新海报可以覆盖旧海报.求最后能看到多少张海报 sol:线段树成段更新.铺第i张海报的时候更新sg[i].x~sg[i].y这一段为i. 然而坐标 ...
- POJ 2528 (线段树 离散化) Mayor's posters
离散化其实就是把所有端点放在一起,然后排序去个重就好了. 比如说去重以后的端点个数为m,那这m个点就构成m-1个小区间.然后给这m-1个小区间编号1~m-1,再用线段树来做就行了. 具体思路是,从最后 ...
- poj 2528 线段树 离散化的小技巧
题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报思路:直接搞超时+超内存,需要离散化.离散化简单的来说就是只取我们需要的值来 用,比如说区间[1000,2000],[1990,2012] ...
- Mayor's posters POJ - 2528(线段树 + 离散化)
Mayor's posters Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 74745 Accepted: 21574 ...
- POJ 2528 线段树
坑: 这道题的坐标轴跟普通的坐标轴是不一样的-- 此题的坐标轴 标号是在中间的-- 线段树建树的时候就不用[l,mid][mid,r]了(这样是错的) 直接[l,mid][mid+1,r]就OK了 D ...
- Mayor's posters POJ - 2528 线段树区间覆盖
//线段树区间覆盖 #include<cstdio> #include<cstring> #include<iostream> #include<algori ...
- Mayor's posters POJ - 2528 线段树(离散化处理大数?)
题意:输入t组数据,输入n代表有n块广告牌,按照顺序贴上去,输入左边和右边到达的地方,问贴完以后还有多少块广告牌可以看到(因为有的被完全覆盖了). 思路:很明显就是线段树更改区间,不过这个区间的跨度有 ...
- poj 2886 线段树+反素数
Who Gets the Most Candies? Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 12744 Acc ...
随机推荐
- [转载]HTML5开发入门经典教程和案例合集(含视频教程)
http://www.iteye.com/topic/1132555 HTML5作为下一代网页语言,对Web开发者而言,是一门必修课.本文档收集了多个HTML5经典技术文档(HTML5入门资料.经典) ...
- TreeSet按value排序
今天学习到TreeSet,但是它是按照key的值来排序的,那如果我们想要按照value的值排序呢?这个问题我上网看了好久,终于找到一个比较易懂的例子: 例:(统计输入数字的个数) 话不多说,看代码就懂 ...
- ASP.NET配置文件Web.config 详细解释
一.认识Web.config文件 Web.config文件是一个XML文本文件,它用来储存 ASP.NET Web 应用程序的配置信息(如最常用的设置ASP.NET Web 应用程序的身份验证方式), ...
- 简单理解 NP, P, NP-complete和NP-Hard
P是一类可以通过确定性图灵机(以下简称 图灵机)在多项式时间(Polynomial time)内解决的问题集合. NP是一类可以通过非确定性图灵机( Non-deterministic Turing ...
- Struts S2-052漏洞利用之Meterpreter(CVE-2017-9805)
Struts S2-052漏洞爆出来已经快一周了,大家可能更想知道其危害~鸡肋? 这里就直接给出漏洞利用拿Meterpreter的过程,想了解更多的请参考其他文章,下面是实验演示部分.Struts S ...
- 回顾一些较简单的dp题
1.导弹拦截 (+贪心) 两问:一个导弹拦截系统最多能拦多少导弹 要拦截所有导弹至少需要多少拦截系统 第一问感觉是一个比较巧妙的方法: 维护一个单调递减的序列 length[] 记录的是拦截导弹的高 ...
- C# Json字符串反序列化
using DevComponents.DotNetBar; using MyControl; using Newtonsoft.Json; using System; using System.Co ...
- 树形dp(B - Computer HDU - 2196 )
题目链接:https://cn.vjudge.net/contest/277955#problem/B 题目大意:首先输入n代表有n个电脑,然后再输入n-1行,每一行输入两个数,t1,t2.代表第(i ...
- Android Framebuffer介绍及使用【转】
转自:https://www.jianshu.com/p/df1213e5a0ed 来自: Android技术特工队 作者: Aaron 主页: http://www.wxtlife.com/ 原文连 ...
- python网络编程-socket“粘包”(小数据发送问题)
一:什么是粘包 “粘包”, 即服务器端你调用时send 2次,但你send调用时,数据其实并没有立刻被发送给客户端,而是放到了系统的socket发送缓冲区里,等缓冲区满了.或者数据等待超时了,数据才会 ...