这困扰我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; }