http://acm.hdu.edu.cn/showproblem.php?pid=1828
扫描线第二题,1A
思路:按照x轴和y轴各扫一次,也就是分两次计算,一次计算与x轴平行的周长 ,另一次与y轴,他们的和就是总周长.
每条边分左右两种边插进去线段树,线段树的cnt维护这个线段[l,r]已经被覆盖了多少次
1.如果左边线段覆盖 那么这一段上面全部+1;
2.如果右边 -1;
这样我们就知道在任意的区间有没有被覆盖过,被覆盖过了多少次;
1.当左边的边覆盖cnt为0的区域的时候,周长加上这段的没有被覆盖的长度
2.当右边的边减去覆盖,这时线段的cnt为1,减去后就变成0了,也就是出去的那条边的周长也要计算进去,所以答案也加上这段的长度;
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define lc idx<<1
#define rc idx<<1|1
#define mid ((l+r)>>1)
#define lson lc,l,mid
#define rson rc,mid,r
#define whole idx,l,r
using namespace std;
const int MAXN=10000*2+2;
struct Scanline
{
int x,yu,yd,v;
Scanline(){}
Scanline(int xx,int yy,int yyyy,int vv) :x(xx),yu(yy),yd(yyyy),v(vv) {}
bool operator <(const Scanline &a) const
{
return x<a.x;
}
};
vector<Scanline> a,b;
class SGtree
{
private:
int cnt[MAXN<<2];
public:
void build(int idx,int l,int r)
{
cnt[idx]=0;
if(l+1==r) return ;
build(lson);
build(rson);
}
void PushDown(int idx,int l,int r)
{
if(cnt[idx]!=-1)
{
cnt[lc]=cnt[rc]=cnt[idx];
cnt[idx]=-1;
}
}
int update(int idx,int l,int r,int x,int y,int v)
{
int ret=0;
if(x<=l && r<=y && cnt[idx]!=-1)
{
cnt[idx]+=v;
if(cnt[idx]==0 || (v==1 && cnt[idx]==1))
return r-l;
}
else
{
PushDown(whole);
if(x<mid) ret+=update(lson,x,y,v);
if(y>mid) ret+=update(rson,x,y,v);
}
return ret;
}
};
int n;
SGtree tree;
int sumup(vector<Scanline> &a)
{
sort(a.begin(),a.end());
int ret=0;
tree.build(1,1,MAXN);
for(int i=0;i<a.size();i++)
{
Scanline x=a[i];
int p=tree.update(1,1,MAXN,x.yd,x.yu,x.v);
ret+=p;
}
return ret;
}
int main()
{
while(~scanf("%d",&n))
{
a.clear();
b.clear();
int x1,y1,x2,y2;
for(int i=0;i<n;i++)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
x1+=10000;
y1+=10000;
x2+=10000;
y2+=10000;
a.push_back(Scanline(x1,y2,y1,1));
a.push_back(Scanline(x2,y2,y1,-1));
b.push_back(Scanline(y1,x2,x1,1));
b.push_back(Scanline(y2,x2,x1,-1));
}
int ans=0;
ans+=sumup(a);
ans+=sumup(b);
printf("%d\n",ans);
}
return 0;
}