http://acm.hdu.edu.cn/showproblem.php?pid=1828
大佬博客链接:点击打开链接
用扫描线求周长,线段树的应用,以下代码给的是弱智的做法,虽然是参考并学习了大佬的博客但毕竟是我写的。分别计算一次x方向、y方向的周长,这题不需要离散化。要这样对横向线段进行操作:读入并记录每个矩形左右范围,以及y坐标,以及所有点所处的区间[l,r],这也是线段树建树的区间。类似于平时所见的(1,n)。然后按照y坐标从小到大对数组中每条线段进行更新,并且线段树要记录cnt值,即矩形的入边为1出边为-1,然后在push_up时按照cnt值判断。这里最关键的点是在线段树中叶子节点是(t,t)的意义其实是[t,t+1),也就是长度为1的线段(当且仅当在被覆盖时)。别的博客中也有提到,可以这样理解,对于一条线段[l,r],其实际上是覆盖了 l,l+1...,r-1这些个点,所以自然可以写出这样的域[l,r),左闭右开,这时对右端点实际上是无影响的,此时相当于已经把整个图形走完了。有关代码讲两个我思考了很久的地方,在update时因为是更新了线段树,所以自然r要减1才能符合我们上面的目的。另外一个地方就是push_up,虽然在学习大佬博客时我看出了这就是push_up,并且昨晚很无脑地套用了,因为感觉是对的。然而今天早上还是想了很久,当然前面实际上也说到了,在更新时有cnt值的叶子肯定是1,明显嘛r-l+1=1呀。但是没有覆盖就应该是0,所以要先判是否被覆盖,再判叶子,其他就把左右子树给加一加。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
const int N=5007;
int ans;
struct node
{
int l,r,h;
int v;
node(){}
node(int a,int b,int c,int d):l(a),r(b),h(c),v(d){}
bool operator <(const node& rhs)const
{
return h<rhs.h;
}
}fx[N<<1],fy[N<<1];//
struct rw
{
int l,r,cnt,len;
}tt[maxn<<2];
void build(int k,int l,int r)
{
tt[k].l=l,tt[k].r=r,tt[k].cnt=tt[k].len=0;
if(l==r) return;
int mid=(l+r)>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
}
void push_up(int k)
{
if(tt[k].cnt)
{
tt[k].len=tt[k].r-tt[k].l+1;
}
else if(tt[k].l==tt[k].r) tt[k].len=0;
else tt[k].len=tt[k<<1].len+tt[k<<1|1].len;
}void update(int l,int r,int k,int v)
{
if(tt[k].l>=l&&tt[k].r<=r)
{
tt[k].cnt+=v;
push_up(k);
return;
}
int mid=(tt[k].l+tt[k].r)>>1;
if(l<=mid) update(l,r,k<<1,v);
if(r>mid) update(l,r,k<<1|1,v);
push_up(k);
}
void solve(int l,int r,struct node d[],int n)
{
build(1,l,r-1);
int tmp=0,pre=0;
for(int i=0;i<n;i++)
{
update(d[i].l,d[i].r-1,1,d[i].v);
tmp+=abs(tt[1].len-pre);
pre=tt[1].len;
}
ans+=tmp;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n==0) break;
int i=0,j=0;
int maxx=-maxn,minx=maxn,maxy=-maxn,miny=maxn;
for(;i<n;i++,j+=2)
{
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
maxx=max(maxx,x2),minx=min(minx,x1);
maxy=max(maxy,y2),miny=min(miny,y1);
fx[j]=node(x1,x2,y1,1);
fx[j+1]=node(x1,x2,y2,-1);
fy[j]=node(y1,y2,x1,1);
fy[j+1]=node(y1,y2,x2,-1);
}
sort(fx,fx+j);
sort(fy,fy+j);
ans=0;
solve(minx,maxx,fx,j);
solve(miny,maxy,fy,j);
printf("%d\n",ans);
}
}