这道题做得真心不容易,首先是离散化纠结了许久,然后就是线段树竟然还会写得有漏洞,最后就是数据范围了,这题的数据超强的啊,最后结果要用__int64,但我还是忽略了中间计算过程也会超范围,最后各种无语。。。
然后说下这题的思路吧,由于坐标的变化范围很大,而城市最多只有40000个(其实是400000个,奉献了几个re),所以很容易想到用离散化。离散化后接下来就是插入线段了,计算面积时当然就要知道这段的最大高度了。但此处有个小技巧,如果我们按照数据给定的顺序插的话,在插入的过程中我们就需要加判断,这样难免显得会很麻烦,因此我们可以对数据按照高度从小到大进行排序,再按这个顺序插入线段。
#include <iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=40100;
struct house
{
int l,r,h;
bool operator<(const struct house t)const
{
return h<t.h;
}
}h[maxn];//离散化后的
struct pp
{
int id,key;
bool isLeft;
bool operator<(const struct pp t)const
{
return key<t.key;
}
}q[maxn*2];//离散化前的
struct node
{
__int64 l,r,h;
}p[maxn*4];
int index[maxn];//映射数组
void build_tree(int l,int r,int rt)
{
p[rt].l=l;
p[rt].r=r;
p[rt].h=0;
if(l==r-1)
return;
int mid=(l+r)>>1;
build_tree(l,mid,rt<<1);
build_tree(mid,r,rt<<1|1);
}
void init(int n)
{
int i,j,k;
for(i=1,j=1;i<=n;i++)
{
scanf("%d",&q[j].key);
q[j].isLeft=true;
q[j].id=i;
j++;
scanf("%d",&q[j].key);
q[j].isLeft=false;
q[j].id=i;
j++;
scanf("%d",&h[i].h);
}
sort(q+1,q+j);
for(i=1,k=0;i<j;i++)
{
if(q[i].key!=q[i-1].key)
index[++k]=q[i].key;
if(q[i].isLeft)
h[q[i].id].l=k;
else
h[q[i].id].r=k;
}
sort(h+1,h+n+1);//对离散后的数据按高度排序
build_tree(1,k,1);
}
__int64 query(int rt)
{
if(p[rt].h)
return p[rt].h*(index[p[rt].r]-index[p[rt].l]);//此处计算可能超范围
else if(p[rt].l==p[rt].r-1)
return 0;
return query(rt<<1)+query(rt<<1|1);
}
void insert(int l,int r,int d,int rt)
{
if(p[rt].l==l&&p[rt].r==r)
{
p[rt].h=d;
return;
}
if(p[rt].h)//下传
{
p[rt<<1].h=p[rt<<1|1].h=p[rt].h;
p[rt].h=0;
}
int mid=(p[rt].l+p[rt].r)>>1;
if(r<=mid)
insert(l,r,d,rt<<1);
else if(l>=mid)
insert(l,r,d,rt<<1|1);
else
{
insert(l,mid,d,rt<<1);
insert(mid,r,d,rt<<1|1);
}
}
int main()
{
int n;
scanf("%d",&n);
init(n);
for(int i=1;i<=n;i++)
insert(h[i].l,h[i].r,h[i].h,1);
printf("%I64d\n",query(1));
return 0;
}
/*
5
1 5 10
2 6 30
3 7 20
4 6 15
5 10 5
*/