[BZOJ1645]City Horizon 城市地平线(离散化+线段树)
Description
约翰带着奶牛去都市观光。在落日的余晖里,他们看到了一幢接一幢的摩天高楼的轮廓在地平线上形成美丽的图案。以地平线为 X 轴,每幢高楼的轮廓是一个位于地平线上的矩形,彼此间可能有重叠的部分。奶牛一共看到了 N 幢高楼,第 i 幢楼的高度是 Hi,两条边界轮廓在地平线上的坐标是Ai 到 Bi。请帮助奶牛们计算一下,所有摩天高楼的轮廓覆盖的总面积是多少。
Input Format
第一行:单个整数 N ,1 ≤ N ≤ 40000• 第二行到第 N + 1 行:第 i + 1 行有三个整数 Ai,Bi 和 Hi,1 ≤ Ai < Bi ≤ 10^9, 1 ≤ Hi ≤10^9
Output Format
单个整数:表示摩天高楼轮廓所覆盖的总面积
Solution
容易想到将坐标离散化,
然后考虑按高度升序排序后用线段树维护,
就变成了区间加问题
Code
#include <cstdio>
#include <algorithm>
#define ll long long
#define MID int mid=(l+r)>>1,ls=id<<1,rs=id<<1|1
#define N 40010
using namespace std;
struct info{
int pos,id;
friend bool operator < (info a,info b){
return a.pos<b.pos;
}
}s[N<<1];
struct house{
int l,r,h;
friend bool operator < (house a,house b){
return a.h<b.h;
}
}A[N];
int n,tp,tag[N<<3],rk[N<<1];
ll T[N<<3];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void pushdown(int l,int r,int id){
if(!tag[id]) return;
MID;
T[ls]=(rk[mid]-rk[l])*1ll*tag[id],
T[rs]=(rk[r]-rk[mid])*1ll*tag[id];
tag[ls]=tag[rs]=tag[id];
tag[id]=0;
}
void updata(int l,int r,int id,int ql,int qr,int v){
//修改+更新答案一起
if(ql<=l&&r<=qr){
T[id]=(rk[r]-rk[l])*1ll*v;
tag[id]=v;
return;
}
pushdown(l,r,id);
MID;
if(qr<=mid) updata(l,mid,ls,ql,qr,v);
else if(ql>=mid) updata(mid,r,rs,ql,qr,v);
else updata(l,mid,ls,ql,qr,v),updata(mid,r,rs,ql,qr,v);//为了更新答案
T[id]=T[ls]+T[rs];
}
int main(){
n=read();
for(int i=1;i<=n;++i){
s[(i<<1)-1].pos=A[i].l=read();
s[(i<<1)].pos=A[i].r=read();
A[i].h=read();
s[(i<<1)-1].id=s[(i<<1)].id=i;
}
sort(s+1,s+(n<<1)+1);
for(int i=1;i<=(n<<1);++i){
if(s[i].pos>rk[tp]) rk[++tp]=s[i].pos;
if(s[i].pos==A[s[i].id].l) A[s[i].id].l=tp;
else A[s[i].id].r=tp;
}
sort(A+1,A+n+1);
for(int i=1;i<=n;++i) updata(1,tp,1,A[i].l,A[i].r,A[i].h);
printf("%lld\n",T[1]);
return 0;
}