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
",ans);
131     }
132     return 0;
133 }

 

原文地址:https://www.cnblogs.com/yuanbo123/p/5511254.html