POJ2528 Mayor'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,所以这里通过使用对区间的离散化来缩小查找范围。参考了一些大牛博客,简单说一下。

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

有一条1到10的数轴(长度为9),给定4个区间[2,4] [3,6] [8,10] [6,9]。现在我们抽取这4个区间的8个端点,2 4 3 6 8 10 6 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~10、1~4、7~10,就有区间[1,10],[1,4],[7,10]。

按照上述方法离散化后的到区间[1,4],[1,2],[3,4]。答案为2,实际上答案为3。

因为上述做法忽略了区间[2,3]的存在,也就是原来的5~6这一块。

新的离散方法为:在相差大于1的数间加一个数(我选择加入两个数的中间值),这样的含义是用一个数字来表示其中间的那块区间,解决某块区间被忽略的问题。

例如在上面1 4 6 10中,

X[ 1 ] = 1, X[ 2 ]=2,X[ 3 ] = 4,X[ 4 ] = 5, X[ 5 ] = 7,X[ 6 ]=8, X[ 7 ] = 10

这样之后,第一次是1~7被染成1;第二次1~3被染成2;第三次5~7被染成3

最终,1~3为2,4为1,5~7为3,于是输出正确结果3。

代码:

  1 #include<iostream>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define LC(a) ((a<<1))
  5 #define RC(a) ((a<<1)+1)
  6 #define MID(a,b) ((a+b)>>1) 
  7 using namespace std; 
  8 typedef long long ll;
  9 const int N=5e4*4;
 10 
 11 struct node{
 12     ll l,r;
 13     ll color;//颜色为-1表示混合色 
 14 }tree[N];
 15 
 16 struct knode{
 17     ll l,r;//用来存储题目给定的区间 
 18 }tmp[N];
 19 
 20 ll ans[N];//记录颜色i是否存在 
 21 ll Hash[N];//存储坐标映射 
 22 ll point[N];//存储坐标序列  
 23 //下推 
 24 void pushdown(ll p){
 25     tree[RC(p)].color=tree[LC(p)].color=tree[p].color;
 26 }
 27 //上推 
 28 void pushup(ll p){
 29     tree[p].color=(tree[LC(p)].color==tree[RC(p)].color?tree[LC(p)].color:-1);
 30 }
 31 
 32 void build(ll p,ll l,ll r){
 33     tree[p].l=l;
 34     tree[p].r=r;
 35     tree[p].color=0;
 36     if(l==r){
 37         return;
 38     }
 39     build(LC(p),l,MID(l,r));
 40     build(RC(p),MID(l,r)+1,r);
 41 }
 42 
 43 void update(ll p,ll l,ll r,ll color){
 44     if(r<tree[p].l||l>tree[p].r)
 45         return;
 46     if(l<=tree[p].l&&r>=tree[p].r){
 47         tree[p].color=color;        
 48         return;
 49     }
 50     //**释放lazy标记
 51     if(tree[p].color!=-1){
 52         pushdown(p);
 53     }
 54     update(LC(p),l,r,color);
 55     update(RC(p),l,r,color);
 56     pushup(p);
 57 }
 58 
 59 void query(ll p,ll l,ll r){
 60     if(r<tree[p].l||l>tree[p].r)
 61         return;
 62     //纯色,不用再找下去 
 63     if(tree[p].color!=-1){
 64         ans[tree[p].color]=1;
 65         return;
 66     }        
 67     query(LC(p),l,r);
 68     query(RC(p),l,r);
 69 }
 70 
 71 //二分查找 
 72 ll Bin_search(ll l,ll r,ll x){
 73     ll mid;
 74     while(l<=r){
 75         mid=(l+r)/2;
 76         if(x==Hash[mid])    return mid;
 77         if(x<Hash[mid])     r=mid-1;
 78         else if(x>Hash[mid])    l=mid+1;
 79     }
 80     return -1;
 81 }
 82 
 83 int main(){
 84     ios::sync_with_stdio(false);
 85     ll t,n;
 86     cin>>t;
 87     while(t--){
 88         cin>>n;     
 89         //***对输入数据进行离散化
 90         ll m1=0;
 91         
 92         for(int i=1;i<=n;i++){
 93             ll l,r;
 94             cin>>tmp[i].l>>tmp[i].r;
 95             point[++m1]=tmp[i].l;
 96             point[++m1]=tmp[i].r;
 97         }
 98         sort(point+1,point+1+m1);
 99         ll m2=0;
100         for(int i=1;i<=m1;i++){
101             if(point[i]!=point[i-1]){
102                 if(point[i]-point[i-1]>1&&i!=1){    
103                     Hash[++m2]=(point[i]+point[i-1])>>1;
104                     Hash[++m2]=point[i];
105                 }
106                 else
107                     Hash[++m2]=point[i];
108             }
109         }
110         //**建树 
111         build(1,1,m2);
112         for(int i=1;i<=n;i++){
113             ll l=Bin_search(1,m2,tmp[i].l);
114             ll r=Bin_search(1,m2,tmp[i].r);
115             update(1,l,r,i);
116         }
117         memset(ans,0,sizeof(ans));
118         query(1,1,m2);
119         ll cnt=0;
120         for(int i=1;i<=m2;i++){
121             if(ans[i]){
122                 cnt++;
123             }        
124         } 
125         cout<<cnt<<endl;
126     }
127 }
原文地址:https://www.cnblogs.com/fu3638/p/7137189.html