这困扰我N久的题目,终于过了。
求N个矩形的周长并,一开始觉得太遥不可及了,感觉好复杂 ,总想先搞懂计算的方法,再看大牛的方法,可是N久之后,对那个方法还是一知半解;
今天结合了代码还有下面俩副图之后,突然觉得豁然开朗啦,自己敲了一遍代码……
重点:我觉得,最重要的就是理解下面三个式子了,理解了之后,就知道该怎么建立线段树了;
ans+=num[1]*(ss[i+1].x-ss[i].x);(横边)
ans+=abs(len[1]-last);(竖边)
last=len[1];
对所有的竖边按照x值从小到排序,之后按顺序插入线段树;
ans累加的是最终结果,num[1]是整个区间内连续的线段数(将竖边投影到y轴的区间),len[1]表示整个区间内被覆盖的长度,而last保存的是上一次的len[1];
也就是说,从左往右在每一次插入一条边后,周长并的累加值==新增的横边+新增的竖边。
我们可以发现,插入一条边之后,新增的横边的树木等于区间内连续线段的数目*新增横边的长度,新增的竖边等于插入前后覆盖长度的差值。
结合下面的图片我们会发现:插入一条出边之后,其实等同于删除该矩形对应的入边。对应下图,此时也就出现了不连续的线段了。横边也相应增加了。
注意:不需要重复建树,因为插入所有边后,相对的也将树中可能产生影响的域给清空了。
结合代码吧:
#include<iostream>
#include<algorithm>
#define maxn 20010
using namespace std;
struct node
{
int x,y1,y2,s;
node(int a=0,int b=0,int c=0,int d=0):x(a) , y1(b) , y2(c) , s(d) {}
friend bool operator <(const node a,const node b)
{
return a.x<b.x;
}
};
node ss[maxn>>1];//保存矩形的边,其中s表示该边为入边还是出边
bool cmp(node a,node b)
{
return a.x<b.x;
}
bool lb[maxn<<2],rb[maxn<<2];
int cnt[maxn<<2],len[maxn<<2],num[maxn<<2];
//len[]表示该区间被覆盖的总长度
//num[]表示该区间内连续的线段数目
//cnt[]表示该区间被覆盖的次数
void PushUp(int k,int s,int t)
{
if(cnt[k])
{
lb[k]=rb[k]=1;
num[k]=2;
len[k]=t-s+1;
}
else if(s==t)
lb[k]=rb[k]=num[k]=len[k]=0;
else {
num[k]=num[k<<1]+num[k<<1 |1];
len[k]=len[k<<1]+len[k<<1 |1];
lb[k]=lb[k<<1];
rb[k]=rb[k<<1|1];
if(rb[k<<1] && lb[k<<1 |1])//左右子区间的有一个线段相连
num[k]-=2;
}
}
void update(int l,int r,int c,int s,int t,int k)
{
if(l<=s && t<=r)
{
cnt[k]+=c;//插边或删边
PushUp(k,s,t);
return ;
}
int kl=k<<1,kr=kl+1,mid=(s+t)>>1;
if(l<=mid)
update(l,r,c,s,mid,kl);
if(r>mid)
update(l,r,c,mid+1,t,kr);
PushUp(k,s,t);
}
int main()
{
int a,b,c,d,n;
int miny,maxy;
while(scanf("%d",&n)==1)
{
int m=0;
miny=10000;
maxy=-10000;
for(int i=0;i<n;i++)
{
scanf("%d %d %d %d",&a,&b,&c,&d);
miny=min(miny,b);
maxy=max(maxy,d);
ss[m++]=node(a,b,d,1);
ss[m++]=node(c,b,d,-1);
}
sort(ss,ss+m);
int ans=0,last=0;
for(int i=0;i<m;i++)
{
if(ss[i].y1<ss[i].y2)
update(ss[i].y1,ss[i].y2-1,ss[i].s,miny,maxy-1,1);
ans+=num[1]*(ss[i+1].x-ss[i].x);
ans+=abs(len[1]-last);
last=len[1];
}
printf("%d\n",ans);
}
return 0;
}