【线段树+离散化】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要开到三倍,因为不仅要考虑左右边界均放进来,而且还要考虑中间增添上来离散化的数字。

 

  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 }

 

原文地址:https://www.cnblogs.com/iiyiyi/p/5027826.html