贴海报 (线段树染色-离散化

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;
}

原文地址:https://www.cnblogs.com/-ifrush/p/10614246.html

时间: 2024-08-03 12:48:31

贴海报 (线段树染色-离散化的相关文章

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

Mayor&#39;s posters---poj2528线段树、离散化

题目链接:http://poj.org/problem?id=2528 题意:有n张海报要贴,每张需要用的区间为L到R,后面的可以贴在之前的上面,就是吧之前的挡住,求最后我们能看到几张海报: 我们可以倒着处理,因为最后贴的我们是能看到的:如果区间被贴过了result不加,没有贴过就+1并标记一下: 由于数据范围太大所以用线段树 #include<stdio.h> #include<math.h> #include<string.h> #include<algori

poj2528 Mayor&#39;s posters(线段树,离散化)

离散化的思想: 对于这样的数据 (3,10000), (9,1000000), (5,100000), (1,1000), (7,1000000) 我们可以将其处理为 (2,7), (5,9), (3,8), (1,6), (4,9) 我们再对离散化之后的数据进行处理就行了. 题目意思: n(n<=10000)个人依次贴海报,给出每张海报所贴的范围li,ri(1<=li<=ri<=10000000). 求出最后还能看见多少张海报. 参考代码: #include <iostre

POJ2528Mayor&#39;s posters 线段树,离散化技巧

题意:一个坐标轴从1~1e7,每次覆盖一个区间(li,ri),问最后可见区间有多少个(没有被其他区间挡住的) 线段树,按倒序考虑,贴上的地方记为1,每次看(li,ri)这个区间是否全是1,全是1就说明在它后面贴的把它给挡住了,否则该海报可见. 然后就愉快的MLE了.... 再看看数据范围,离散化如下,比如如果海报的左右端点如下 那图中橙色的一块的大小其实对结果没有影响,可以把他们都缩为1 最后离散化结果如下图: 代码: 1 #include <algorithm> 2 #include <

poj2299--B - Ultra-QuickSort(线段树,离散化)

Ultra-QuickSort Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 41215   Accepted: 14915 Description In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swappin

ZOJ1610 Count the Colors 经典线段树染色问题

题意,给你n个  x,y,c,意思就是区间[x,y]被染成C色,但是颜色会被覆盖的,染色操作完成以后 问你每种颜色有多少段 并输出颜色编号id跟段数cnt 经典问题,不过写的有点撮吧,没去看别人的,这个方法应该是最传统的最普通的,常规的开数组记录,也许大神们有更高端的方法 #include<iostream> #include<cstdio> #include<list> #include<algorithm> #include<cstring>

POJ 3277 City Horizon(线段树+扫描线+离散化)

题目地址:POJ 3277 水题..稍微处理一下然后用求面积并的方法求即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <

hdu1542 Atlantis (线段树+扫描线+离散化)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9032    Accepted Submission(s): 3873 Problem Description There are several ancient Greek texts that contain descriptions of the fabled i

NC15667 统计颜色(线段树染色)

一道线段树染色,但是这里是桶,我犯了经验主义以为是覆盖问题 数据不大,用二进制表示即可 #include<iostream> #include<algorithm> #include<stack> #include<vector> #include<cstring> using namespace std; typedef long long ll; const int N=1e5+10; const int mod=1e9+7; int n,m