题目大意

在墙上贴海报,墙壁是由一排连续的瓷砖铺成,海报贴在墙壁上必须占据连续的几块瓷砖,海报可以互相覆盖,问最后可以看见几张海报(未被完全覆盖)。

题目分析

墙壁是由连续的一个区间构成,每个海报占据几块瓷砖,即占据一个区间。每次进行贴海报,是进行区间操作,而最后查询有多少个海报可见也是对区间进行查询。对区间进行操作,考虑使用线段树

由于瓷砖数目太大 100000000,直接进行构建线段树会超内存,也会超时。因此需要进行离散化之后再使用线段树: 
    当所有的海报都铺完毕之后,会将墙壁分割成多个连续的区间(由海报的左右两边作为边界),这些区间长度不固定,但是将他们视为相同的一个单元并不影响结果,因此将所有的瓷砖离散化为 这些由海报的边缘分割出来的单元。 
    当张贴海报p的时候,确定该海报占据离散化之后的那些单元区间,然后将该区间标记为海报p;之后再次贴海报p1时,覆盖了海报p的一部分,需要更新之前p覆盖的单元的标记。由于线段树的特点,可以在标记的时候延迟标记。 
    张贴完所有海报之后,进行查询。从线段树的根节点开始递归查询,看节点代表的区间被那个海报完全覆盖。这样可以确定有哪些海报最终可见。

实现(c++)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<vector>
#include<string.h>
#include<algorithm>
using namespace std;#define MAX_POSTER_NUM 10001             //海报最多张数
#define MAX_SEG_NUM 2*MAX_POSTER_NUM     //由海报边缘确定的最多的分段数
#define MAX_NODE_NUM 4*MAX_SEG_NUM       //线段树的节点最多#define MIN(a, b) a < b? a : b
#define MAX(a, b) a > b? a : b
struct Node{int left;               //该节点代表的离散化之后区间的起始点序号int right;             //该节点代表的离散化之后区间的终止点序号int beg_byte;          //该节点代表离散化之后的区间起始点  代表的起始瓷砖号int end_byte;           //该节点代表离散化之后的区间终止点  代表的终止瓷砖号int top_cover_num;      //该节点代表的离散化之后区间被 那块海报完全覆盖,没被任何瓷砖完全覆盖则为-1
};
Node gNodes[MAX_NODE_NUM];struct Poster{int left;           //海报占据瓷砖区间的开始int right;         //海报占据瓷砖区间的结束
};struct SegUnit{int beg;           //离散化之后的区间 的起始瓷砖号int end;           //离散化之后的区间 的终止瓷砖号
};
SegUnit gSegUnit[MAX_SEG_NUM];
Poster gPosters[MAX_POSTER_NUM];
int gSegUnitNum;        //离散化之后的总区间数目vector<int> gPartPoint;  //用于离散化区间
int gVisibleCount[MAX_POSTER_NUM];  //判断海报是否可见//构建线段树, left, right 为离散化之后区间的起始和结束; index为线段树节点编号
void BuildSegTree(int left, int right, int index){gNodes[index].left = left;gNodes[index].right = right;gNodes[index].top_cover_num = -1;if (left == right){gNodes[index].beg_byte = gSegUnit[left].beg;gNodes[index].end_byte = gSegUnit[left].end;return;}int left_child = 2 * index + 1, right_child = 2 * index + 2;int mid = (left + right) / 2;BuildSegTree(left, mid, left_child);BuildSegTree(mid + 1, right, right_child);//父节点的起始和结束的瓷砖编号由 左右子节点决定gNodes[index].beg_byte = gNodes[left_child].beg_byte;gNodes[index].end_byte = gNodes[right_child].end_byte;
}//离散化
void InitSegUnit(){gSegUnitNum = 0;for (int i = 0; i < gPartPoint.size() - 1; i++){      gSegUnit[gSegUnitNum].beg = gPartPoint[i];gSegUnit[gSegUnitNum].end = gPartPoint[i + 1];gSegUnitNum++;}
}
//更新,节点index 之前被某张海报完全覆盖,现在又有新的海报完全或者部分覆盖index。则将index的top_cover_num 更新
void PushDown(int index){int left_child = 2 * index + 1;int right_child = 2 * index + 2;gNodes[left_child].top_cover_num = gNodes[index].top_cover_num;gNodes[right_child].top_cover_num = gNodes[index].top_cover_num;
}//贴海报
void Post(int poster_num, int poster_beg, int poster_end, int index){if (gNodes[index].beg_byte >= poster_beg && gNodes[index].end_byte <= poster_end){gNodes[index].top_cover_num = poster_num;return;}else if (gNodes[index].beg_byte > poster_end || gNodes[index].end_byte < poster_beg){return;}if (poster_beg >= poster_end){return;}int left_child = 2 * index + 1, right_child = 2 * index + 2;int left_beg = gNodes[left_child].beg_byte, left_end = gNodes[left_child].end_byte,right_beg = gNodes[right_child].beg_byte, right_end = gNodes[right_child].end_byte;if (gNodes[index].top_cover_num != -1){PushDown(index);gNodes[index].top_cover_num = -1;}Post(poster_num, poster_beg, MIN(left_end, poster_end), left_child);Post(poster_num, MAX(right_beg, poster_beg), poster_end, right_child);
}//统计有多少海报是可见的
void CalVisibleSeg(int index){if (gNodes[index].top_cover_num != -1){gVisibleCount[gNodes[index].top_cover_num] = 1;return;}if (gNodes[index].left == gNodes[index].right){return;}int left_child = 2 * index + 1;int right_child = 2 * index + 2;CalVisibleSeg(left_child);CalVisibleSeg(right_child);
}void debug(int index){printf("index  = %d, left = %d, right = %d, beg_byte = %d, end_byte = %d, top_num = %d\n", index, gNodes[index].left,gNodes[index].right, gNodes[index].beg_byte, gNodes[index].end_byte, gNodes[index].top_cover_num);if (gNodes[index].left == gNodes[index].right){return;}int left = 2 * index + 1;int right = 2 * index + 2;debug(left);debug(right);
}
int main(){int cas, poster_num;scanf("%d", &cas);while (cas--){scanf("%d", &poster_num);gPartPoint.clear();gPartPoint.reserve(poster_num * 2);memset(gVisibleCount, 0, sizeof(gVisibleCount));for (int i = 0; i < poster_num; i++){scanf("%d %d", &gPosters[i].left, &gPosters[i].right);gPosters[i].right++;     // 将闭区间转换为开区间 [i, j] 覆盖i,i+1, ..j 瓷砖,//转换为 [i, j +1), 也表示覆盖 i,i+1, ..j 瓷砖gPartPoint.push_back(gPosters[i].left);gPartPoint.push_back(gPosters[i].right);}//离散化sort(gPartPoint.begin(), gPartPoint.end());vector<int>::iterator it = unique(gPartPoint.begin(), gPartPoint.end());gPartPoint.erase(it, gPartPoint.end());InitSegUnit();BuildSegTree(0, gSegUnitNum - 1, 0);for (int i = 0; i < poster_num; i++){Post(i, gPosters[i].left, gPosters[i].right, 0);}CalVisibleSeg(0);int result = 0;for (int i = 0; i < poster_num; i++){result += gVisibleCount[i];}printf("%d\n", result);}return 0;
}

转载于:https://www.cnblogs.com/gtarcoder/p/4783636.html

poj_2286 线段树相关推荐

  1. 二逼平衡树——树套树(线段树套Splay平衡树)

    题面 Bzoj3196 解析 线段树和Splay两棵树套在一起,常数直逼inf,但最终侥幸过了 思路还是比较简单, 在原数组维护一个下标线段树,再在每一个线段树节点,维护一个对应区间的权值Splay. ...

  2. 线段树——HDU - 1698

    题目含义 就是初始化一堆数为1 可以经过操作把一个区间的数都改变 并求这堆数的总大小 题目分析 有一个 #include<iostream> #include<stdio.h> ...

  3. BZOJ.1558.[JSOI2009]等差数列(线段树 差分)

    BZOJ 洛谷 首先可以把原序列\(A_i\)转化成差分序列\(B_i\)去做. 这样对于区间加一个等差数列\((l,r,a_0,d)\),就可以转化为\(B_{l-1}\)+=\(a_0\),\(B ...

  4. 【线段树分治 线性基】luoguP3733 [HAOI2017]八纵八横

    不知道为什么bzoj没有HAOI2017 题目描述 Anihc国有n个城市,这n个城市从1~n编号,1号城市为首都.城市间初始时有m条高速公路,每条高速公路都有一个非负整数的经济影响因子,每条高速公路 ...

  5. [bzoj1582][Usaco2009 Hol]Holiday Painting 节日画画_线段树

    Holiday Painting 节日画画 bzoj-1582 Usaco-2009 Hol 题目大意:给定两个n*m的01网格图.q次操作,每次将第二个网格图的子矩阵全部变成0或1,问每一次操作后两 ...

  6. codefores 786B. Legacy(最短路,线段树优化拆点,好题)

    题目链接 B. Legacy time limit per test2 seconds memory limit per test256 megabytes inputstandard input o ...

  7. 【题解】BZOJ 3065: 带插入区间K小值——替罪羊树套线段树

    题目传送门 题解 orz vfk的题解 3065: 带插入区间K小值 系列题解 一 二 三 四 惨 一开始用了一种空间常数很大的方法,每次重构的时候merge两颗线段树,然后无限RE(其实是MLE). ...

  8. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  9. bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治

    这题真是十分难写啊 不管是点分治还是括号序列都有一堆细节.. 点分治:时空复杂度$O(n\log^2n)$,常数巨大 主要就是3个堆的初始状态 C堆:每个节点一个,为子树中的点到它父亲的距离的堆. B ...

  10. POJ 2528 Mayor's posters(线段树)

    题目大意 贴海报.每张海报的高度都是一样的,唯独宽度不一样.每张海报只能占用整数倍的单位线段长度,贴了 n(n<=10000) 张海报之后,有几张能够看见(有一个角能看见这张海报也算被看见了)? ...

最新文章

  1. Windows下命令行及Java+Tesseract-OCR对图像进行(字母+数字+中文)识别,亲测可行
  2. 依赖类型dependency type在maven中的作用
  3. 基于JavaScript技术的横排文字转古书式竖排工具
  4. gbdt 算法比随机森林容易_随机森林与GBDT
  5. IIS 7.0探索用于 Windows Vista 的 Web 服务器和更多内容
  6. 【python命名规范】谷歌风格命名
  7. 汇编的一些坑以及部分上机题目的实现
  8. Web Hacking 101 中文版 十、跨站脚本攻击(一)
  9. windows performance
  10. DELPHI 中的自定义类笔记(一) OBJECT 创建类 不用 CREATE 【转】
  11. tomcat 原理与使用资料
  12. Android Studio下JUnit单元测试
  13. RSA算法详解及手算过程
  14. 阿里企业邮箱收费版与免费版有哪些规格和功能上的区别?
  15. 海尔跨越福特、丰田制造标杆主导世界制造业国际标准
  16. phpMyAdmin下载
  17. 数据科学 IPython 笔记本 7.2 数据整理
  18. 宽搜入门代码模板详解 HDOJ1253
  19. python3 输入数字_python怎么输入数字
  20. MAC上自定义Office word快捷键

热门文章

  1. 少样本学习系列(二)【Model-Based Methods】
  2. rsa加解密及加签验签
  3. MariaDB基本操作--(创建用户)(转)
  4. javascript traverse object attributes 遍历对象属性
  5. PLAY2.6-SCALA(五) Action的组合、范围的设置以及错误的处理
  6. UVa 714 抄书(贪心+二分)
  7. Qt中QBitmap 的使用 --QBitmap的作用
  8. 从微博部分功能学习UWP技术
  9. 什么是 Linux 发行版
  10. 配置Windows Server 2008 允许多用户远程桌面连接