PKU 3327City Horizon离散化+线段树

所谓离散化(这里讨论一维离散化),就是一个直线上的点集,我们忽略他们之间的距离大小,只考虑他们的相对位置,这就是离散化
比如点集1 5 8 3可以离散化成1 3 4 2这样子他们的相对位置不变,但是最高位点就大大缩小了,解决了线段树的空间要求

如何实行离散化: 我们可以开一个数组 a[1] = 1, a[3] = 4. a[4] = 8, a[2] = 3这样子就可以完成离散后的点对原点的映射,那么反过来呢,我们可以使用2分查找,lgn复杂度找到原点到离散后的点的映射。

解决了线段树的空间问题,这题就变得很容易了,我们要求矩形的并,而且这题所有矩形的低端都是对齐的,所以我们不用考虑低端,只需考虑高度和水平距离,这恰好符合一维线段树,每次插入一个矩形,我们就可以插入这段水平边,然后记录它的高度,最后就很方便的统计面积了。

 

 

 

#include <algorithm>
#include <iostream>
using namespace std;
const int N=40010;

struct tree
{
 __int64 l,r;//是离散化的点的位次
 __int64 high;
}t[8*N];

struct Point
{
 int beg,end;
 int hi;
}dia[N];

int node[2*N];
int all;

void maketree(int c,int l,int r)
{
 t[c].l = l;
 t[c].r = r;
 t[c].high = 0;
 if(l+1==r)
 { 
  return ;
 }
 int mid = (l+r)>>1;
 maketree(c*2,l,mid);
 maketree(2*c+1,mid,r);
}

void update(int c,int l,int r,int num)
{
 if(t[c].l==l && t[c].r==r)
 {
  t[c].high = num;
  return ;
 }
 if(t[c].high != 0)
 {
  t[2*c].high = t[2*c+1].high = t[c].high;
  t[c].high = 0;
 }
 int mid = (t[c].l + t[c].r) >> 1;
 if(r<=mid)
  update(2*c,l,r,num);
 else if(l>=mid)
  update(2*c+1,l,r,num);
 else
 {
  update(2*c,l,mid,num);
  update(2*c+1,mid,r,num);
 }
}

long long findans(int c)
{
 __int64 sum1,sum2;
 if(t[c].high != 0 || t[c].l+1 == t[c].r)
 {
  return (__int64) (t[c].high * ( node[t[c].r]-node[t[c].l]) );
 }
 else
 {
  sum1 = findans(c*2);
  sum2 = findans(c*2+1);
  return sum1 + sum2;
 }
}

int f(int num)
{
 int l=1,r=all;
 while(l<=r)
 {
  int mid = (l+r)>>1;
  if(num == node[mid])
   return mid;
  if(num < node[mid])
   r = mid - 1;
  else
   l = mid + 1;
 }
}  

int cmp(const void *a,const void *b)
{
 if( (*(Point *)a).hi ==(*(Point *)b).hi)
  return (*(Point *)a).beg-(*(Point *)b).beg;
 else
  return (*(Point *)a).hi-(*(Point *)b).hi;
}
int main()
{
 int n,i;
 __int64 ans=0;
 int cnt = 1;
 scanf("%d",&n);
 for(i=0;i<n;i++)
 {
  scanf("%I64d %I64d %I64d",&dia[i].beg,&dia[i].end,&dia[i].hi);
  node[cnt++] = dia[i].beg;
  node[cnt++] = dia[i].end;
 }
 sort(node+1,node+cnt);
 all = 1;
 for(i=2;i<cnt;i++)
 {
  while(i < cnt && node[i] == node[i-1]) i++;
  if(i!=cnt)
   node[++all] = node[i];
 }
 qsort(dia,n,sizeof(dia[0]),cmp);
 maketree(1,1,all);
 for(i=0;i<n;i++)
 {
  int b=f(dia[i].beg);
  int e=f(dia[i].end);
  //cout << b << " " << e <<endl;
  update(1,b,e,dia[i].hi);
 }
 printf("%I64d/n",findans(1));
 return 0;
}//PS:PKU数据超恶心!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值