题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1828
题意:求重叠矩形的周长
思路:也是运用了扫描线,每一次更新后的tsum减去之前的tsum就是这次周长增长(上边处理理解有些不同,画了张图理解),由于周长要计算所有的边要到cnt(面积只要到cnt-1
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 20030
using namespace std;
struct Tree
{
int l,r;
int tsum,snum;
}tree[maxn*3];
int lazy[maxn*3],lseg[maxn*3],rseg[maxn*3],cnt,pos[maxn];
struct Node
{
int l,r,h,date;
}s[maxn];
bool cmp(Node p,Node q)
{
return p.h<q.h;
}
void getlen(int root)
{
if(lazy[root])
{
tree[root].tsum=pos[tree[root].r+1]-pos[tree[root].l];
lseg[root]=1;
rseg[root]=1;
tree[root].snum=2;
}
else if (tree[root].l==tree[root].r)
{
tree[root].tsum=0;
lseg[root]=0;
rseg[root]=0;
tree[root].snum=0;
}
else
{
tree[root].tsum=tree[root<<1].tsum+tree[root<<1|1].tsum;
tree[root].snum=tree[root<<1].snum+tree[root<<1|1].snum;
lseg[root]=lseg[root<<1];
rseg[root]=rseg[root<<1|1];
if (rseg[root<<1] && lseg[root<<1|1]) tree[root].snum-=2;
}
}
void build(int root,int l,int r)
{
tree[root].l=l;
tree[root].r=r;
tree[root].tsum=tree[root].snum=0;
if (l==r) return;
int mid=(tree[root].l+tree[root].r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
}
void update(int root,int l,int r,int val)
{
if (tree[root].l>=l && tree[root].r<=r)
{
lazy[root]+=val;
getlen(root);
return;
}
int mid=(tree[root].l+tree[root].r)>>1;
if (l<=mid) update(root<<1,l,r,val);
if (r>mid) update(root<<1|1,l,r,val);
getlen(root);
}
void getline(int l,int r,int h,int val)
{
s[cnt].l=l;
s[cnt].r=r;
s[cnt].h=h;
s[cnt].date=val;
cnt++;
}
int main()
{
int n,num;
while (scanf("%d",&n)!=EOF)
{
cnt=0;
num=0;
memset(lazy,0,sizeof(lazy));
memset(lseg,0,sizeof(lseg));
memset(rseg,0,sizeof(rseg));
for (int i=0;i<n;i++)
{
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
getline(x1,x2,y1,1);
getline(x1,x2,y2,-1);
pos[num++]=x1;
pos[num++]=x2;
}
sort(s,s+cnt,cmp);
sort(pos,pos+num);
int tem=1,last=0,res=0;
for (int i=1;i<num;i++)
{
if (pos[i]!=pos[i-1])
pos[tem++]=pos[i];
}
build(1,0,tem);
s[cnt].h=s[cnt-1].h;
for (int i=0;i<cnt;i++)
{
int l=lower_bound(pos,pos+tem,s[i].l)-pos;
int r=lower_bound(pos,pos+tem,s[i].r)-pos-1;
update(1,l,r,s[i].date);
res+=abs(last-tree[1].tsum);
res+=tree[1].snum*(s[i+1].h-s[i].h);
last=tree[1].tsum;
}
printf("%d\n",res);
}
}
),snum是来保存没有被覆盖的竖边,lseg和rseg是标记该区间是否被覆盖,如果左子树的rseg和右子树的lseg被覆盖就代表有2个矩形是重叠的因此snum数目需要-2
扫描线走到A的时候,将边1的区间标记,tsum加上边1的长度(初始为0),减去last的长度(初始为0)
扫描线走到B的时候,将边2的区间标记,tsum加上边2没有和边1重合的长度,减去last长度(上一步的tsum)
扫描线走到C的时候,和上2步类似
扫描线走到D的时候,由于边4是上边,边4的区间标记-1,但是由于其他边已经覆盖该区间,tsum没有影响
扫描线走到E的时候,边5的区间-1,tsum减去标记为0的区间,在和last的差值就是该位置增加的区间