poj2528 线段树 离散化

本文介绍了一道关于在墙上贴海报并计算可见海报数量的问题。通过使用离散化和线段树的方法来解决大规模数据输入的问题。文章详细解释了如何通过离散化减少坐标范围,以及如何利用线段树进行区间更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

  如题:http://poj.org/problem?id=2528

 

 

   在墙上贴一堆海报,一张海报可以覆盖已经贴上的海报,求贴完湖还可以见到的海报的数量

 

   这一题墙的长度给的范围太大,直接用线段树分区间肯定超时,超内存,必须离散化。海报最多10000张。用结构体poster【i】.coord记录海报的坐标。然后排序,去掉重复,并一次编号.这个编号就是离散化后的结果.然后对左右编号区间贴海报(线段树节点更新)。

  

#include<iostream>
using namespace std;
#define N 10005 //海报数量

int result;
int l[N];
int r[N];
bool mark[N];

struct line
{
 int kind; //kind表示贴的第几张海报,贴完后,当kind=0,代表者一个区间被一张以上的海报贴满,这个区间可能看见的海报已经被更新到子节点。
 int left,right;
}lines[10*N];

struct item
{
 int coord; // 海报左,右的坐标
 int id;
}poster[2*N];

int cmp(const void * a,const void * b) //升序排序
{
 return ((item *)a)->coord-((item *)b)->coord;
}

void build(int s,int t,int node)
{
 lines[node].left=s;
 lines[node].right=t;
 if(s==t) return;
 int mid=(lines[node].left+lines[node].right)/2;
 build(s,mid,node*2);
 build(mid+1,t,node*2+1);
}
void update(int s,int t,int node,int cover)
{
 if(lines[node].left==s&&lines[node].right==t)
 {
  lines[node].kind=cover;
 return;
 }
 if(lines[node].kind!=0&&lines[node].kind!=cover)
 {
  lines[node*2].kind=lines[node*2+1].kind=lines[node].kind;
  lines[node].kind=0; //这个区间被不止一个海报完全覆盖
 }
 int mid=(lines[node].left+lines[node].right)/2;
 if(t<=mid)
  update(s,t,node*2,cover);
 else if(s>mid)
  update(s,t,node*2+1,cover);
 else
 {
  update(s,mid,node*2,cover);
  update(mid+1,t,node*2+1,cover);
 }
}
void cal(int node)
{
 if(lines[node].kind!=0)
 {
  if(mark[lines[node].kind]==false)
  {
   mark[lines[node].kind]=true;
   result++;
  }
 }
 else
 {
  cal(node*2);
  cal(node*2+1);
 }
}
int main()
{
 int t,n,i,j;
 struct item *templ,*tempr,tl,tr;
 scanf("%d",&t);
 while(t--)
 {
  memset(lines,0,sizeof(lines));
  memset(poster,0,sizeof(poster));
  memset(mark,false,sizeof(mark));
  scanf("%d",&n);
  for(i=j=1;i<=n;i++)
  {
   scanf("%d %d",&l[i],&r[i]);
   poster[j++].coord=l[i];
   poster[j++].coord=r[i];
  }
  //准备离散
  qsort(poster+1,n*2,sizeof(item),cmp);
  for(i=j=1;i<=2*n;i++,j++)
  {
   poster[j].coord=poster[i].coord;
   poster[j].id=j;
   while(poster[i].coord==poster[i+1].coord)
    i++;
  }
  build(1,j-1,1);
  for(int i=1;i<=n;i++)
  {
   tl.coord=l[i];
   tr.coord=r[i];
   templ=(item *)bsearch(&tl,poster+1,j,sizeof(item),cmp);
   tempr=(item *)bsearch(&tr,poster+1,j,sizeof(item),cmp);
   update(templ->id,tempr->id,1,i);  //i当前第i张海报
  }
  result=0;
  cal(1);
  printf("%d\n",result);
 }
 return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值