hdu1828 线段树+离散化+扫描线

时间:2023-12-16 22:08:08

添加lb[],rb[]数组,来标记竖边。添加num,来计算竖边的个数,因为计算周长的时候,未覆盖的竖边都要加。

#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define maxn 10010
struct seg
{
int l,r,h;
int f;
}s[maxn<<];
struct node
{
int cnt;
int num;
int len;
}tree[maxn<<];
int lb[maxn<<],rb[maxn<<];
int mark[maxn];
bool cmp(seg a,seg b)
{
return a.h < b.h;
}
void build(int l,int r,int rt)
{
tree[rt].cnt=;
tree[rt].len=;
tree[rt].num=;
if(l==r)
return ;
int m=(l+r)/;
build(lson);
build(rson);
}
void getlen(int l,int r,int rt)
{
if(tree[rt].cnt)//如果这一段被全部覆盖
{
tree[rt].len=mark[r+]-mark[l];
tree[rt].num=;//整段覆盖,那就有2条竖直的边
lb[rt]=rb[rt]=;//标记左右的竖直线段
}
else if(l==r)
{
tree[rt].num=tree[rt].len=;
lb[rt]=rb[rt]=;
}
else //未整段覆盖;
{
tree[rt].num=tree[rt<<].num+tree[rt<<|].num;
tree[rt].len=tree[rt<<].len+tree[rt<<|].len;
lb[rt]=lb[rt<<];rb[rt]=rb[rt<<|];
if(lb[rt<<|]&&rb[rt<<])//此线段已相连
tree[rt].num-=;
}
}
void updata(int L,int R,int c,int l,int r,int rt)
{
if(l>=L&&R>=r)
{
tree[rt].cnt+=c;
getlen(l,r,rt);
return ;
}
int m=(l+r)/;
if(m>=L)
updata(L,R,c,lson);
if(R>m)
updata(L,R,c,rson);
getlen(l,r,rt);
}
int find(int val,int len)
{
int l,r,m;
l=;
r=len;
while(l<=r)
{
m=(l+r)/;
if(val==mark[m])
return m;
else if(val>mark[m])
l=m+;
else r=m-;
}
return -;
}
int main()
{
int i,n,m;
while(scanf("%d",&n)!=EOF)
{
int x1,y1,x2,y2;
m = ;
for(i=;i<n;i++)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
s[m].l = x1; s[m].r = x2; s[m].h = y1; s[m].f = ; mark[m++] = x1;
s[m].l = x1; s[m].r = x2; s[m].h = y2; s[m].f = -; mark[m++] = x2;
}
sort(mark,mark+m);
sort(s,s+m,cmp);
int k = ;
for(i=;i < m;i++)
{
if(mark[i]!=mark[i-])
mark[k++]=mark[i];
}
build(,k-,);
int ans=;
int past=;
for(i=;i<m;i++)
{
int l=find(s[i].l,k-);
int r=find(s[i].r,k-)-;
updata(l,r,s[i].f,,k-,);
ans+=(tree[].num*(s[i+].h-s[i].h));
ans+=abs(tree[].len-past);
past=tree[].len;
}
printf("%d\n",ans);
}
}