POJ 2528(线段树+离散化)

POJ 2528(线段树+离散化)

http://acm.pku.edu.cn/JudgeOnline/problem?id=2528
这是一道经典的 线段树题目,另外加上离散化的方法。
    离散化:由于题目中wall有10000000bytes long,直接线段树无疑会MLE。所以要对其离散化,基本做法是:先对所有端点坐标进行排序,用 相应序号代替端点坐标构造线段树进行计算。这样最大的序号也只是2*n。
   在构造线段树的节点结构体时,添加变量c。c=0时表示c线段没有贴海报,或者贴了不止一张海报;c>0时表示贴了一张海报,并且c的值表示贴的是第几张海报。
    线段树更新的基本原理就是,当我们贴海报i时,如果遇到某一线段区间能够被当前海报完全覆盖,那么我们更新到此区间即可,即让它的变量c更新为海报i,记录下i的值。如果不能被海报完全覆盖,则只是这一线段区间的部分区间需要修改,则更改这一区间的子区间即可。
  1  #include < iostream >
  2  #include < cstdio >
  3  #include < algorithm >
  4  #include < string .h >
  5  #define  MAX 20001
  6 
  7  using   namespace  std;
  8 
  9  int  c,n,ls[MAX];
 10  struct  node{
 11       int  l,r;
 12       int  c;
 13  }tree[MAX * 4 ];
 14  struct  ln{
 15       int  li,num;//num表示第几张海报
 16  }line[MAX];
 17  int   set [MAX][ 2 ];
 18  bool  visit[MAX];
 19  int  ans;
 20 
 21  bool  cmp( struct  ln a, struct  ln b){
 22       return  a.li < b.li;
 23  }
 24 
 25  void  Inittree( int  pos, int  ll, int  rr){
 26      tree[pos].l  =  ll;
 27      tree[pos].r  =  rr;
 28      tree[pos].c  =   0 ;
 29       if (ll != rr){
 30           int  mid  =  (ll + rr) >> 1 ;
 31          Inittree(pos * 2 ,ll,mid);
 32          Inittree(pos * 2 + 1 ,mid + 1 ,rr);
 33      }
 34  }
 35 
 36  void  Insert( int  pos, int  ll, int  rr, int  color){
 37       if (tree[pos].l  ==  ll  &&  tree[pos].r  ==  rr){
 38          tree[pos].c  =  color;
 39           return ;
 40      }
 41       if (tree[pos].c  >   0   &&  tree[pos].c  !=  color){
 42          tree[pos * 2 ].c  =  tree[pos].c;
 43          tree[pos * 2 + 1 ].c  =  tree[pos].c;
 44          tree[pos].c  =   0 ;
 45      }
 46       int  mid  =  (tree[pos].l  +  tree[pos].r) >> 1 ;
 47       if (rr <= mid){
 48          Insert(pos * 2 ,ll,rr,color);
 49      }
 50       else   if (ll > mid){
 51          Insert(pos * 2 + 1 ,ll,rr,color);
 52      }
 53       else {
 54          Insert(pos * 2 ,ll,mid,color);
 55          Insert(pos * 2 + 1 ,mid + 1 ,rr,color);
 56      }
 57  }
 58 
 59  void  Search( int  pos){
 60       if (tree[pos].c != 0 ){
 61           if ( ! visit[tree[pos].c]){ // tree[pos].c
 62              visit[tree[pos].c]  =   true ;
 63              ans ++ ;
 64          }
 65           return  ;
 66      }
 67      Search( 2 * pos);
 68      Search( 2 * pos + 1 );
 69  }
 70 
 71  int  main()
 72  {
 73       int  i;
 74       while (scanf( " %d " , & c) != EOF){
 75           while (c -- ){
 76              scanf( " %d " , & n);
 77               for (i  =   0 ;i  <  n; ++ i){ //离散化
 78                  scanf( " %d%d " , & set [i][ 0 ], & set [i][ 1 ]);
 79                  line[ 2 * i].li  =   set [i][ 0 ];
 80                  line[ 2 * i].num  =   - (i + 1 );//用负数表示 线段起点
 81                  line[ 2 * i + 1 ].li  =   set [i][ 1 ];
 82                  line[ 2 * i + 1 ].num  =  i + 1 ;
 83              }
 84              sort(line,line + 2 * n,cmp);
 85               int  temp  =  line[ 0 ].li,tp  =   1 ;
 86               for (i  =   0 ;i  <   2 * n; ++ i){
 87                   if (line[i].li  !=  temp){
 88                      tp ++ ;
 89                      temp  =  line[i].li;
 90                  }
 91                   if (line[i].num  <   0 ){
 92                       set [ - line[i].num - 1 ][ 0 =  tp;
 93                  }
 94                   else {
 95                       set [line[i].num - 1 ][ 1 =  tp;
 96                  }
 97              } //离散化
 98          
 99              Inittree( 1 , 1 ,tp);
100               for (i  =   0 ;i  <  n; ++ i){
101                  Insert( 1 , set [i][ 0 ], set [i][ 1 ],i + 1 );
102              }
103              memset(visit, 0 , sizeof (visit));
104              ans  =   0 ;
105              Search( 1 );
106              printf( " %d\n " ,ans);
107          }
108      }
109       return   0 ;
110  }
111 

你可能感兴趣的:(POJ 2528(线段树+离散化))