【线段树+离散化】POJ2528-Mayor's posters

【题目大意】

在墙上贴海报,问最后能看到几张海报?

【注意点】

1.首先要注意这是段线段树,而非点线段树。读题的时候注意观察图。来看discuss区下面这组数据:

5 6

4 5

6 8

上面数据的答案应该是2,注意观察图,覆盖的是区间。

2.离散化

由于覆盖的是区间,不能简单的离散化,否则会出现差错。比如说下面这组数据:

1 5

1 3

4 5

以及

1 5

1 2

4 5

如果简单离散化都会变成:

1 4

1 2

3 4

最后得出只能看到两张海报的结论,而事实上第一组数据中能够看到三张海报,为了解决这个问题,如果相邻两个数之间相差大于1,就补上一个中间的数字。

比如说1 4,离散化成为1 2 3

3.数据范围:线段树要开到<<4,至于为什么还没有研究出来。X要开到三倍,因为不仅要考虑左右边界均放进来,而且还要考虑中间增添上来离散化的数字。

 【线段树+离散化】POJ2528-Mayor's posters_第1张图片

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define lson l,m,rt<<1
 6 #define rson m+1,r,rt<<1|1
 7 /*define后面绝对不能加分号*/
 8 using namespace std;  9 const int MAXN=10000+50;  10 int l[MAXN],r[MAXN];  11 int X[MAXN*3],t,M;  12 int col[MAXN<<4];  13 int hash[MAXN];  14 /*延迟标记当前区域被编号为几的覆盖*/ 
 15 int ans;  16 
 17 void pushdown(int rt)  18 {  19     if (col[rt]!=-1)  20  {  21         col[rt<<1]=col[rt];  22         col[rt<<1|1]=col[rt];  23         col[rt]=-1;  24  }  25 }  26 
 27 int Bin(int key)  28 {  29     int ub=1,lb=M+1;  30     while (lb>ub)  31  {  32         int m=(ub+lb)/2;  33         if (X[m]==key) return m;  34         if (X[m]>key) lb=m;  35             else (ub=m);  36  }  37     return -1;  38 }  39 
 40 void update(int L,int R,int l,int r,int rt,int cit)  41 {  42     if (L<=l && r<=R)  43  {  44         col[rt]=cit;  45         return;  46  }  47  pushdown(rt);  48     int m=(l+r)>>1;  49     if (L <= m) update(L,R,lson,cit);  50     if (m < R) update(L,R,rson,cit);  51 }  52 
 53 void query(int l,int r,int rt)  54 {  55     if (col[rt]!=-1)  56  {  57         if (hash[col[rt]]!=1) ans++;  58         hash[col[rt]]=1;  59         return;  60  }  61     if (l==r) return;  62     int m=(l+r)>>1;  63  query(lson);  64  query(rson);  65 }  66 
 67 
 68 void init()  69 /*输入数据并进行离散化*/
 70 {  71     int num=0;  72     scanf("%d",&t);  73     for (int i=0;i<t;i++)  74  {  75         scanf("%d%d",&l[i],&r[i]);  76         X[++num]=l[i];  77         X[++num]=r[i];  78  }  79     sort(X+1,X+num+1);  80     /*M来记录离散化之后总共出现了几个数字*/
 81     M=1;  82     /*注意因为下面的for循环是从2开始的,所以m的初始值要是1,否则第一个数字会被覆盖掉*/
 83     for (int i=2;i<=num;i++)  84  {  85         if (X[i]!=X[i-1]) X[++M]=X[i];  86         /*重复的数字只记录一次*/
 87  }  88     num=M;  89     for (int i=2;i<=num;i++)  90  {  91         if (X[i]-X[i-1]>1) X[++M]=X[i]-1;  92         /*离散化时要注意,如果两个点相差大于1,则在中间再插入一个数字*/
 93  }  94     sort(X+1,X+M+1);  95 }  96 
 97 void submain()  98 {  99     memset(col,-1,sizeof(col)); 100     for (int i=0;i<t;i++) 101  { 102         int lp=Bin(l[i]); 103         int rp=Bin(r[i]); 104         update(lp,rp,1,M,1,i); 105         /*二分查找左边界和右边界离散化后对应的数值*/
106  } 107 } 108 
109 int main() 110 { 111     int T; 112     scanf("%d",&T); 113     for (int kase=0;kase<T;kase++) 114  { 115  init(); 116  submain(); 117         ans=0; 118         memset(hash,0,sizeof(hash)); 119         query(1,M,1); 120         cout<<ans<<endl; 121  } 122     return 0; 123 }

 

你可能感兴趣的:(【线段树+离散化】POJ2528-Mayor's posters)