poj2528线段树解题报告,离散化+线段树

题目网址:http://poj.org/problem?id=2528

题意:

  n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000)。

求出最后还能看见多少张海报。

  输入:

 1
 5
 1 4
 2 6
 8 10
 3 4
 7 10 这题用常规思路解题必定TLE,l,r太大;

通俗点说,离散化就是压缩区间,使原有的长区间映射到新的短区间,但是区间压缩前后的覆盖关系不变。举个例子:

有一条1到10的数轴(长度为9),给定4个区间[2,4] [3,6] [8,10] [6,9],覆盖关系就是后者覆盖前者,每个区间染色依次为 1 2 3 4。

现在我们抽取这4个区间的8个端点,2 4 3 6 8 10 6 9

然后删除相同的端点,这里相同的端点为6,则剩下2 4 3 6 8 10 9

对其升序排序,得2 3 4 6 8 9 10

然后建立映射

2     3     4     6     8     9   10

↓     ↓      ↓     ↓     ↓     ↓     ↓

1     2     3     4     5     6     7

那么新的4个区间为 [1,3] [2,4] [5,7] [4,6],覆盖关系没有被改变。新数轴为1到7,即原数轴的长度从9压缩到6,显然构造[1,7]的线段树比构造[1,10]的线段树更省空间,搜索也更快,但是求解的结果却是一致的。

离散化时有一点必须要注意的,就是必须先剔除相同端点后再排序,这样可以减少参与排序元素的个数,节省时间。

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <algorithm>
  4 #include <string.h>
  5 using namespace std;
  6 #define  N  10100
  7 #define    M 10000000
  8 bool vis[2*N];//标记出现过得海报
  9 int x[2*N];
 10 struct T
 11 {
 12      int node,add,l,r;
 13 }tree[M*4];
 14 void creat(int l,int r,int k)//建树
 15 {
 16      tree[k].node=0;
 17      tree[k].l=l;
 18      tree[k].r=r;
 19      tree[k].add=0;
 20      if(l==r)
 21          return;
 22      int mid=(l+r)>>1;
 23      creat(l,mid,k<<1);
 24      creat(mid+1,r,k<<1|1);
 25 }
 26 void pushdown(int k,int color)//延迟标记
 27 {
 28      int x=k<<1;
 29      tree[x].add=1;
 30      tree[x+1].add=1;
 31      tree[x].node=color;
 32      tree[x+1].node=color;
 33      tree[k].add=0;
 34      tree[k].node=0;
 35 }
 36 void Search(int l,int r,int color,int k)//更新线段树
 37 {
 38      if(r<tree[k].l||l>tree[k].r)
 39          return ;
 40      if(l<=tree[k].l&&r>=tree[k].r)
 41      {
 42          tree[k].node=color;
 43          tree[k].add=1;
 44          return ;
 45      }
 46      if(tree[k].add)
 47          pushdown(k,tree[k].node);
 48      int mid=(tree[k].l+tree[k].r)>>1;
 49      if(r<=mid)
 50          Search(l,r,color,k<<1);
 51      else if(l>mid)
 52           Search(l,r,color,k<<1|1);
 53         else
 54         {
 55              Search(l,mid,color,k<<1);
 56              Search(mid+1,r,color,k<<1|1);
 57         }
 58 }
 59 int ans;
 60 void q(int l,int r,int k)//查找不同颜色的区域
 61 {
 62      if(tree[k].add)
 63      {
 64          if(!vis[tree[k].node])
 65         {
 66           ans++;
 67           vis[tree[k].node]=1;
 68          }
 69          return ;
 70      }
 71      int mid=(l+r)>>1;
 72      q(l,mid,k<<1);
 73      q(mid+1,r,k<<1|1);
 74 }
 75 int s(int l,int r,int k)//二分查找
 76 {
 77     int mid;
 78      while(l<=r)
 79      {
 80          mid=(l+r)>>1;
 81          if(k<x[mid]) r=mid-1;
 82          else if(k>x[mid]) l=mid+1;
 83          else return mid;
 84      }
 85      return -1;
 86 }
 87 int main()
 88 {
 89     int t,n,i,j;
 90     int l[N],r[N];
 91    scanf("%d",&t);
 92     while(t--)
 93     {
 94          j=0;
 95          memset(vis,0,sizeof(vis));
 96          scanf("%d",&n);
 97          for(i=0;i<n;i++)
 98          {
 99              scanf("%d%d",&l[i],&r[i]);
100              x[j++]=l[i];
101              x[j++]=r[i];
102          }
103          sort(x,x+j);
104          int m=1;
105          for(i=0;i<j-1;i++)
106          {
107              if(x[i]==x[i+1])
108             {
109                  m--;
110             }
111             else
112             {
113                  x[i+m]=x[i+1];
114             }
115          }
116          j=j+m-1;
117          sort (x,x+j);
118          /*for(i=0;i<n;i++)
119          {
120              printf("%d %d ",s(0,j-1,l[i])+1,s(0,j-1,r[i])+1);
121              cout<<endl;
122          }*/
123         creat(1,j,1);
124          for(i=0;i<n;i++)
125          {
126              Search(s(0,j-1,l[i])+1,s(0,j-1,r[i])+1,i+1,1);
127          }
128          ans=0;
129        q(1,j,1);
130          printf("%d\n",ans);
131     }
132     return 0;
133 }
时间: 2024-08-28 10:23:42

poj2528线段树解题报告,离散化+线段树的相关文章

OrzFAng 233&ndash;树 解题报告

题目描述 方方方种下了三棵树,两年后,第二棵树长出了n个节点,其中1号节点是根节点. 给定一个n个点的树 支持两种操作 方方方进行m次操作,每个操作为: (1)给出两个数i,x,将第i个节点的子树中,与i距离为斐波那契数的节点权值+x(包括i本身). (2)给出一个数i,求出第i个节点的子树中,与i距离为斐波那契数的节点的权值和(包括i本身).   题解 斐波那契数列 首先这个会被操作的只有大概25层的节点. 这样深度相同的区间在bfs序上是连续的区间,那么只要求出这样的左右端点是哪些,后面的就

[BZOJ1984]月下“毛景树”解题报告|树链剖分

Description 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里.爬啊爬~爬啊爬~~毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~~~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数: ? Change k w:将第k条树枝上毛毛果的个数改变为w个. ? Cover u v w:将节点u与节点

Codeforces 514C. Watto and Mechanism解题报告(字典树)

传送门 题意:给你一个字典和一些询问,问你对于每个询问的字符串必须更改一个字符,能否得到字典中的某一个单词. 思路:先构造一颗字典树,然后搜一遍就行了,要注意strlen不能每次都用,常数很大! #include<bits/stdc++.h> #define rep(i,k,n) for(int i=k;i<=n;i++) using namespace std; const int maxn=300005,maxm=600005; int tree[maxm][5],en[maxm];

「csp校内训练 2019-10-30」解题报告

「csp校内训练 2019-10-30」解题报告 T1.树 题目链接(逃) \(Description\): 现在有一棵树,共 \(N\) 个节点. 规定:根节点为 \(1\) 号节点,且每个节点有一个点权. 现在,有 \(M\) 个操作需要在树上完成,每次操作为下列三种之一: \(1 \ x \ a\):操作 \(1\),将节点 \(x\) 点权增加 \(a\). \(2 \ x \ a\):操作 \(2\),将以节点 \(x\) 为根的子树中所有点的权值增加 \(a\). \(3 \ x\)

POJ2528 Mayor&#39;s posters(线段树染色问题+离散化)

题目大意:有t组数据,每组数据给你n张海报(1<=n<=10000),下面n组数据分别给出每张海报的左右范围(1 <= l <= r <= 10000000),下一张海报会覆盖前一张海报,求最后可见(包括完全和不完全可见)的海报有几张. 例如: 1 5 1 4 2 6 8 10 3 4 7 10 如上图所示,答案为4. 解题思路:其实这是一道区间染色问题,但是由于查找区间太大,显然直接建树会导致MLE,所以这里通过使用对区间的离散化来缩小查找范围.参考了一些大牛博客,简单说一

[BZOJ3065]带插入区间K小值 解题报告 替罪羊树+值域线段树

刚了一天的题终于切掉了,数据结构题的代码真**难调,这是我做过的第一道树套树题,做完后感觉对树套树都有阴影了......下面写一下做题记录. Portal Gun:[BZOJ3065]带插入区间k小值. 这道题的题面其实都提醒怎么做了,维护区间k小值用值域线段树,但要维护一个插入操作,树状数组套主席树也用不了,那么这道题还剩下平衡树可以搞,那就上平衡树吧. 我这里的做法,因为要维护序列的顺序,所以我这里用到替罪羊树套值域线段树:我们在替罪羊树的每个节点都套一颗值域线段树,记录以该节点为根的子树的

ACM: Just a Hook 解题报告 -线段树

E - Just a Hook Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive met

POJ - 2528 Mayor&#39;s posters (离散化+线段树区间修改)

https://cn.vjudge.net/problem/POJ-2528 题意 给定一些海报,可能相互重叠,告诉你每个海报的宽度(高度都一样的)和先后叠放顺序,问没有被完全盖住的有多少张? 分析 海报最多10000张,但是墙有10000000块瓷砖长,海报不会落在瓷砖中间. 如果直接建树,就算不TLE,也会MLE.即单位区间长度太多. 其实10000张海报,有20000个点,最多有19999个区间.对各个区间编号,就是离散化.然后建树. 可以直接进行区间修改,最后再统计. 这里采用比较巧妙的

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

题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值.由于l和r范围比较大,内存就不够了,所以就用离散化的技巧 比如将1 4化为1 2,范围缩小,但是不影响答案. 写了这题之后对区间更新的理解有点加深了,重点在覆盖的理解(更新左右两个孩子节点,然后值清空),还是要多做做题目. 1 #include <iostream> 2 #include <