1. 程式人生 > >貼海報 (線段樹染色-離散化

貼海報 (線段樹染色-離散化

顏色 pen 避免 unique 因此 mes for push sort

n(n<=10000) 個人依次貼海報,給出每張海報所貼的範圍li,ri(1<=li<=ri<=10000000) 。求出最後還能看見多少張海報。

雖然之前學過離散化,但用的時候就想不起來 emm;

10000個海報 最多有10000個區間 20000個坐標值,遠少於10000000,因此采用離散化

將離散化後的坐標對應數組下標儲存到線段樹中 ;

染色區間是整段的,本身就可以看做 lazy標記 ,需要下推函數;

下推 :

void push_down(int pos){
     if(  col[pos]==-1 )return ;
     col[pos<<1]=col[pos<<1
|1]=col[pos]; col[pos]=-1; return ; }

染色 :

void  updata ( int L  ,int R ,int l ,int r,int pos ,int c ){
     if( l>=L && r<=R){
         col[pos] = c;
         return ;
     }
     push_down(pos);
     int mid= (l+r)>>1;
     if( mid >= L) updata ( L ,R ,l ,mid ,pos<<1
,c); if( mid < R) updata( L ,R ,mid+1 ,r ,pos<<1|1 ,c); return ; }

註意區間的染色情況,要在各區間坐標之間在增加一個取樣;

eg: 線段樹 僅采集坐標端點的線段樹 1~10 -- 1~3 6~10 --1~1 3~3 6~6 10~10

這樣 如 3~6 這個區間之間的顏色就無法判斷;

因此要增加離散化取樣:

//離散化
for( int i=0; i<n ;i++){
            scanf( "%d%d",&pl[i] ,&pr[i]);
            p[cnt
++] = pl[i]; p[cnt++] = pr[i]; p[cnt++] = pr[i]+1; if( pr[i] - pl[i] >1)p[cnt++] =pl[i]+1; } sort( p , p+cnt); int sz = unique( p ,p+cnt) - p;

查詢:

void query( int L ,int R ,int  pos){
      if( col[pos]!=-1 && ! vis[ col[pos]]){
           // cout << col[pos]<<‘ ‘<<L<<‘ ‘<<R<<endl;
           // cout<< p[L]<<‘ ‘<<p[R]<<endl;
          vis [ col[pos] ] = 1;
          ans++;
          return ;
      }
      if( L == R || vis[ col[pos] ])return ;  //最開始只有L==R這個return條件 結果訪問到了不該訪問的點(vis過但有col的點 // push_down(pos);                      // 如果這裏有push_down 也可以避免上述錯誤(在訪問端點之前就將其更新,因此詢問時push_down 可以增加魯棒性
      int  mid =(L +R)>>1;
       query(L ,mid ,pos <<1 );
       query( mid+1 ,R ,pos<<1|1);
      return ;
}
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int pl[10050] ,pr[10050],p[40050];

int col [160050],vis[160050];

int ans =0;
void push_down(int pos){
     if(  col[pos]==-1 )return ;
     col[pos<<1]=col[pos<<1|1]=col[pos];
     col[pos]=-1;
     return ;
}
void  updata ( int L  ,int R ,int l ,int r,int pos ,int c ){
     if( l>=L && r<=R){
         //   cout<< pos<<" "<<c<<endl;
         col[pos] = c;
         return ;
     }
     push_down(pos);
     int mid= (l+r)>>1;
     if( mid >= L) updata ( L ,R ,l ,mid ,pos<<1 ,c);
     if( mid < R) updata( L ,R ,mid+1 ,r ,pos<<1|1 ,c);
     return ;
}
void query( int L ,int R ,int  pos){
      if( col[pos]!=-1 && ! vis[ col[pos]]){
           // cout << col[pos]<<‘ ‘<<L<<‘ ‘<<R<<endl;
           // cout<< p[L]<<‘ ‘<<p[R]<<endl;
          vis [ col[pos] ] = 1;
          ans++;
          return ;
      }
      if( L == R || vis[ col[pos] ])return ;  // 上面下面任選其一即可
      // push_down(pos);
      int  mid =(L +R)>>1;
       query(L ,mid ,pos <<1 );
       query( mid+1 ,R ,pos<<1|1);
      return ;
}
int bond( int n ,int x ,int y ){
         int mid = x+(y-x)/2 ;
         while( p[mid] != n ){
             if( p[mid] > n){
                 y = mid;
             }
             if( p[mid] < n){
                 x= mid+1;
             }
             mid = x+(y-x)/2 ;
         }
         return mid;
}
int main( ){
    freopen( "out.txt" ,"w",stdout);
     int T;
     int n;
     scanf( "%d",&T );
     while ( T--){
            memset( col ,-1 ,sizeof(col));
            memset( vis , 0 ,sizeof(vis));
         scanf("%d",&n);
         int cnt=0;
         for( int i=0; i<n ;i++){
            scanf( "%d%d",&pl[i] ,&pr[i]);
            p[cnt++] = pl[i];
            p[cnt++] = pr[i];
            p[cnt++] = pr[i]+1;
            if( pr[i] - pl[i] >1)p[cnt++] =pl[i]+1;
         }
         sort( p , p+cnt);
         int sz = unique( p ,p+cnt) - p;
      //   for( int i=0 ;i<sz ;i++)cout << p[i]<<" ";
        // cout<<endl;
         for( int i=0 ; i<n ;i++){
             int l= upper_bound(p ,p+sz ,pl[i])-p;
             int r= upper_bound(p ,p+sz ,pr[i])-p;
           //  cout<<l<<" "<<r<<endl;
             updata(l, r, 1 ,sz , 1, i+1);
         }
       //  for( int i=1 ;i<= 12 ;i++)cout <<col[i]<<" ";
         ans= 0;
         query( 1 , sz ,1);
         printf( "%d\n", ans);
     }
     return 0;
}

貼海報 (線段樹染色-離散化