hihoCoder #1079 : 离散化 (线段树,数据离散化)

题意:有一块宣传栏,高一定,给出长度,再给出多张海报的张贴位置,问还能见到几张海报(哪怕有一点被看到)?假设海报的高于宣传栏同高。

思路:问题转成“给出x轴上长为L的一条线段,再用n条线段进行覆盖上去,最后还能看到及条线”。长度是0~L,即长度是L,进行离散化的时候,应该用1~L,每个数字表示一个单位长。还有就是按照提示所给的信息实现即可。步骤如下:

(1)保存n个数据,做成pair,并将所有出现过的数字在另外找地方排序,去掉重复的,再将数据紧缩化处理,那么大小在1~max。再将紧缩化的数据与原数据做成映射表。

(2)建立线段树,原始n个数据进行映射后对线段树插入更新。注意上限的问题,因为已经离散化了。每个节点上有个值val,表示处于此段区间的是编号为val的海报。

(3)DFS搜索线段树,遇到tag=1的节点就进行标记,然后返回,其子树都没用处的,已经被覆盖。可能会有重复的,比如一段为[2,3],一段为[3,5],因为不能放在一起,所以分开放的时候会有重复的val,要去重。

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int N=100010;
  4 int n,l,rr,ll,cnt=0;
  5 bool vis[N];
  6 unordered_map<int,int>  mapp;
  7 pair<int,int>   pai[N];
  8 struct node
  9 {
 10     int val;
 11     bool tag;
 12     node *ll,*rr;
 13 };
 14
 15 node *create()
 16 {
 17     node *tmp=new(node);
 18     tmp->val=tmp->tag=0;
 19     tmp->ll=tmp->rr=0;
 20     return tmp;
 21 }
 22
 23 void update(int l,int r,int LL,int RR,int num,node *t)  //其实可以不用递归,因为不用回溯
 24 {
 25     if(l==LL&&r==RR)//找到了对应区间
 26     {
 27         t->tag=1;
 28         t->val=num;
 29         return ;
 30     }
 31     if( LL!=RR && !t->ll ) //有孩子,但是还没有建立
 32     {
 33         t->ll=create();
 34         t->rr=create();
 35         t->ll->tag= t->rr->tag= 1;
 36         t->ll->val= t->rr->val= t->val;
 37     }
 38
 39     int mid=((LL+RR)>>1);
 40     if(t->tag)//需要对此节点下推
 41     {
 42         if(t->ll)//前提是有孩子
 43         {
 44             t->ll->tag= t->rr->tag= 1;
 45             t->ll->val= t->rr->val= t->val;
 46         }
 47         t->tag=0;
 48     }
 49
 50     if(l>mid)   update(l,r,mid+1,RR,num,t->rr);//在右边
 51     else if(r<=mid) update(l,r,LL,mid,num,t->ll);//在左边
 52     else
 53     {
 54         update(l,mid,LL,mid,num,t->ll);
 55         update(mid+1,r,mid+1,RR,num,t->rr);
 56     }
 57 }
 58
 59 void DFS(int LL,int RR,node *t) //进行深搜,搜到tag为1的就有用,可能存在重复
 60 {
 61     if(t->tag)
 62     {
 63         vis[t->val]=1;//为了去重
 64         return;
 65     }
 66     int mid=((LL+RR)>>1);
 67     DFS(LL,mid,t->ll);
 68     DFS(mid+1,RR,t->rr);
 69 }
 70
 71 int main()
 72 {
 73     //freopen("input.txt", "r", stdin);
 74
 75     cin>>n>>l;
 76     vector<int> vect;   //辅助
 77     for(int i=0; i<n; i++)
 78     {
 79         scanf("%d%d",&ll,&rr);
 80         pai[i]=make_pair(ll,rr);
 81         vect.push_back(ll);
 82         vect.push_back(rr);
 83     }
 84
 85     sort(vect.begin(),vect.end());
 86     vect.push_back(-1);     //仅仅为了下面的for不会溢出。
 87     int up=0;
 88     for(int i=0;i<vect.size()-1; i++)   //紧缩化处理
 89     {
 90         if(vect[i]!=vect[i+1])
 91             mapp[vect[i]]=++up; //做个哈希表
 92     }
 93     vect.clear();
 94
 95     node *tree=create();    //建树根节点
 96     tree->tag=1;
 97
 98     for(int i=0; i<n; i++)  //根据pair进行修改树。设置tag,在需要修改其儿子时在进行下推。
 99     {
100         int L=mapp[pai[i].first];
101         int R=mapp[pai[i].second];
102         update(L,R-1,1,up-1,i+1,tree);      //插入修改
103     }
104
105     DFS(1,up,tree);//深搜
106     for(int i=1; i<=n; i++)    if(vis[i])  cnt++;
107     cout<<cnt<<endl;
108
109
110     return 0;
111 }

AC代码

时间: 2024-10-29 05:10:28

hihoCoder #1079 : 离散化 (线段树,数据离散化)的相关文章

hiho1079 : 离散化(线段树+区间离散化)

#1079 : 离散化 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho在回国之后,重新过起了朝7晚5的学生生活,当然了,他们还是在一直学习着各种算法~ 这天小Hi和小Ho所在的学校举办社团文化节,各大社团都在宣传栏上贴起了海报,但是贴来贴去,有些海报就会被其他社团的海报所遮挡住.看到这个场景,小Hi便产生了这样的一个疑问--最后到底能有几张海报还能被看见呢? 于是小Ho肩负起了解决这个问题的责任:因为宣传栏和海报的高度都是一样的,所以宣传栏可以被视作

POJ 2528 Mayor&amp;#39;s posters 离散化+线段树

题目大意:给出一些海报和贴在墙上的区间.问这些海报依照顺序贴完之后,最后能后看到多少种海报. 思路:区间的范围太大,然而最多仅仅会有10000张海报,所以要离散化. 之后用线段树随便搞搞就能过. 关键是离散化的方法,这个题我时隔半年才A掉,之前一直就TTT,我还以为是线段树写挂了. 当我觉得我自己的水平这样的水线段树已经基本写不挂的时候又写了这个题,竟然还是T. 后来我对照别人的代码,才发现是我的离散化写渣了. 以下附AC代码(79ms),这个离散化写的比較优雅.时间也非常快,以后就这么写了.

POJ 2528 Mayor&#39;s posters (离散化 + 线段树)

强烈不推荐在POJ做这道题!!! 强烈不推荐在POJ做这道题!!! 强烈不推荐在POJ做这道题!!! 推荐去UVA 10587 或 SCU 2249 POJ的数据比较水且可能有错,一些本来错误的数据但可以水过,以及在UVA与SCU同样题目都能AC的程序在POJ莫名WA了. 建议写完程序后跑下这组数据: 1 3 1 10 1 3 6 10 好多题解的答案是2,但答案明显是3,这是因为每个数字其实表示的是一个单位长度,并非一个点 , 这就会导致像这样的区间: 1-10 1-4 5-10 1-10 1

【POJ】2528 Mayor&#39;s posters ——离散化+线段树

Mayor's posters Time Limit: 1000MS    Memory Limit: 65536K Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral posters at all places at their whim. The city

Mayor&#39;s posters---poj2528线段树、离散化

题目链接:http://poj.org/problem?id=2528 题意:有n张海报要贴,每张需要用的区间为L到R,后面的可以贴在之前的上面,就是吧之前的挡住,求最后我们能看到几张海报: 我们可以倒着处理,因为最后贴的我们是能看到的:如果区间被贴过了result不加,没有贴过就+1并标记一下: 由于数据范围太大所以用线段树 #include<stdio.h> #include<math.h> #include<string.h> #include<algori

poj2528 Mayor&#39;s posters(线段树,离散化)

离散化的思想: 对于这样的数据 (3,10000), (9,1000000), (5,100000), (1,1000), (7,1000000) 我们可以将其处理为 (2,7), (5,9), (3,8), (1,6), (4,9) 我们再对离散化之后的数据进行处理就行了. 题目意思: n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000). 求出最后还能看见多少张海报. 参考代码: #include <iostre

离散化+线段树/二分查找/尺取法 HDOJ 4325 Flowers

题目传送门 题意:给出一些花开花落的时间,问某个时间花开的有几朵 分析:这题有好几种做法,正解应该是离散化坐标后用线段树成端更新和单点询问.还有排序后二分查找询问点之前总花开数和总花凋谢数,作差是当前花开的数量,放张图易理解: 还有一种做法用尺取法的思想,对暴力方法优化,对询问点排序后再扫描一遍,花开+1,花谢-1.详细看代码. 收获:一题收获很多:1. 降低复杂度可以用二分 2. 线段计数问题可以在端点标记1和-1 3. 离散化+线段树 终于会了:) (听说数据很水?) 代码1:离散化+线段树

poj/OpenJ_Bailian - 2528 离散化+线段树

传送门:http://bailian.openjudge.cn/practice/2528?lang=en_US //http://poj.org/problem?id=2528 题意: 给你n长海报,每张海报在墙上贴的区间范围是l,r 问你这n张海报贴完后,可以看见的海报数量是多少 题解: 离散化+线段树 因为l,r的数据范围是1e7,而题目只给了64MB的空间,直接存的话空间会炸掉,所以需用用到离散化的技巧 然后按照端点单点更新即可 现在重新写这题发现这个题坑点在于每一个点他都代表一个长度为

POJ2528Mayor&#39;s posters 线段树,离散化技巧

题意:一个坐标轴从1~1e7,每次覆盖一个区间(li,ri),问最后可见区间有多少个(没有被其他区间挡住的) 线段树,按倒序考虑,贴上的地方记为1,每次看(li,ri)这个区间是否全是1,全是1就说明在它后面贴的把它给挡住了,否则该海报可见. 然后就愉快的MLE了.... 再看看数据范围,离散化如下,比如如果海报的左右端点如下 那图中橙色的一块的大小其实对结果没有影响,可以把他们都缩为1 最后离散化结果如下图: 代码: 1 #include <algorithm> 2 #include <

poj 2528 Mayor&#39;s posters【离散化+线段树】

题目:poj 2528 Mayor's posters 题意:给一个长度非常长的墙上贴长度为ai的海报,由于有的会覆盖掉,求最后能看见的海报个数. 分析:题目和POJ2777 一模一样,方法也一样,只不过这个要离散化,其次要数组开大一点.至少2倍. 离散化的时候用了C++的 pair 类,还是比较好用的. 代码: #include <iostream> #include <algorithm> #include <utility> #include <cstrin