poj上的经典线段树

来源:互联网 发布:进货收货出售软件 编辑:程序博客网 时间:2024/05/16 13:48
题目大意:
有一面海报墙,在墙上顺序贴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 0
原创粉丝点击