题意
给定一些平行于坐标轴的线段,线段的宽度为1,单位线段的面积为 1 .求所有线段的面积(并)的和
思路
只要找出右上角端点,横纵坐标都加 1 存储就行
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define ls rt<<1
#define rs rt<<1|1
#define mid(rt) (p[rt].l+p[rt].r)>>1
using namespace std;
typedef long long ll;
const int maxn=1000010;
int tot;
struct edge
{
ll l,r;
ll h;
int v;
}e[maxn<<2];
bool cmp(edge a,edge b)
{
return a.h<b.h;
}
ll x[maxn<<2];
struct node
{
int l,r;
int cnt;
ll len;
}p[maxn<<2];
void build(int l,int r,int rt)
{
p[rt].l = l , p[rt].r = r;
p[rt].cnt = p[rt].len = 0;
if(l==r)
return ;
int m = mid(rt);
build(l,m,ls);
build(m+1,r,rs);
}
void pushup(int rt)
{
if(p[rt].cnt)
p[rt].len = x[p[rt].r+1] - x[p[rt].l];
else if(p[rt].l==p[rt].r)
p[rt].len = 0;
else
p[rt].len = p[ls].len + p[rs].len;
}
void update(int l,int r,int rt,int v)
{
if(p[rt].l==l && p[rt].r==r)
{
p[rt].cnt += v;
pushup(rt);
return ;
}
int m = mid(rt);
if(r<=m)
update(l,r,ls,v);
else if(l>m)
update(l,r,rs,v);
else
{
update(l,m,ls,v);
update(m+1,r,rs,v);
}
pushup(rt);
}
void pre(ll x1,ll y1,ll x2,ll y2)
{
if(x1>x2)
swap(x1,x2);
if(y1>y2)
swap(y1,y2);
x2 += 1 , y2 += 1;
e[tot].l = e[tot+1].l = x[tot] = x1;
e[tot].r = e[tot+1].r = x[tot+1] = x2;
e[tot].h = y1;
e[tot+1].h = y2;
e[tot].v = 1;
e[tot+1].v = -1;
tot += 2;
}
int main()
{
int n;
tot=0;
ll x1,x2,y1,y2;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
pre(x1,y1,x2,y2);
}
sort(e,e+tot,cmp);
sort(x,x+tot);
int k = unique(x,x+tot)-x;
build(0,k-1,1);
ll ans=0;
for(int i=0;i<tot;i++)
{
int l=lower_bound(x,x+k,e[i].l)-x;
int r=lower_bound(x,x+k,e[i].r)-x-1;
update(l,r,1,e[i].v);
ans += (e[i+1].h-e[i].h)*p[1].len;
}
printf("%lld\n",ans);
return 0;
}