poj上的经典线段树

题目大意:
有一面海报墙,在墙上顺序贴n张海报(海报的高度与墙的高度一样高),墙上有刻度,给出每张海报对应的起始刻度和终止刻度,求最后能看到的海报的数目。
 
解题思路:
线段覆盖的问题,想到用线段树来做。但是由于此题的数据范围太大,需要使用离散化,这里就是把每张海报的起始刻度和终止刻度离散到里一个数组里边,输入的时候海报的刻度信息是存在一个结构体的数组里边,通过离散化的方式,存在了一个连续的一维数组里边。(如果不是很清楚的话,可以通过单步调试的方法,加深理解。)
 
AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 20002
struct poster//海报结构题
{
  int start;//海报的起始刻度
  int end;//海报的终止刻度
};
poster p[N/2];//存储海报信息的结构题数组
int index[N];//离散化后的海报信息存储数组
int part[N];//存储墙上露在外边的海报的编号(一种海报用一个编号标记)
int li_num;//离散后,有多少个不同的起始终止位置
bool see[N/2];//最后用于判断每种海报是否被数过的标记数组
int find(int k)//查找k这个刻度在离散化数组里边的下标
{
  for(int i=0;i<li_num;i++)
  {
    if(index[i]==k)return i;
  }
  return 0;
}
int main()
{
#ifndef ONLINE_JUDGE
  freopen("input.txt","r",stdin);
#endif
  int ca;
  //while(cin>>ca)
  while((scanf("%d",&ca))==1)//使用scanf,一开始用cin超时
  {
    while(ca--)
    {
      int n;
      scanf("%d",&n);//cin>>n;
      for(int i=0;i<n;i++)
      {
        //cin>>p[i].start>>p[i].end;
        scanf("%d%d",&p[i].start,&p[i].end);
        index[2*i]=p[i].start;//离散化处理
        index[2*i+1]=p[i].end;
      }
      int kn=2*n;
      sort(index,index+kn);//对刻度进行排序
      li_num=0;
      for(int i=1;i<kn;i++)
      {
        if(index[i]!=index[i-1])//忽略相同的刻度
          index[li_num++]=index[i-1];
        part[i]=-1;//把墙上每个刻度一开始的海报标记为-1
      }
      index[li_num++]=index[kn-1];
      for(int i=0;i<n;i++)
      {
        int s=find(p[i].start);
        int e=find(p[i].end);
        for(int j=s;j<=e;j++)
        {
          part[j]=i;//按照顺序标记墙上海报的标号
        }
      }
      memset(see,false,sizeof(see));//初始化see数组
      int ans=0;
      for(int i=0;i<li_num;i++)
      {
        if(!see[part[i]])
        {
          ans++;//如果编号为part[i]的海报没有数过,就数一次
          see[part[i]]=true;//标记已经输过了
        }
      }
      cout<<ans<<endl;
    }
  }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值