【题意】
给定n个矩形,求他们的交的周长。
【题解】
以Y轴建立线段树,X轴为扫描方向。
线段树维护这样几个量:
cov:表示线段被覆盖几次
num:该线段有几个被覆盖的区间段
sum:该线段被覆盖的总长度
lcover,rcover:线段左右两边是否被覆盖。
对于竖边,看每次插入线段时sum[1]的增量。
对于横边,看被覆盖的区间段数。
【教训】
一开始计算竖边是不是计算增量,而是算只被覆盖一次的区间长度和,所以繁爆了。
计算增量后,就只算总长即可。
还有,维护的时候要根据cov的值来维护sum,num,还有lcover,rcover(我忘了!)
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=5005,maxl=20005;
struct node
{
int x,y1,y2,kk;
}a[maxn*2];
int sum[maxl*4],num[maxl*4],cov[maxl*4],lcov[maxl*4],rcov[maxl*4];
int ans,tot,n,maxy,x1,x2,y1,y2;
bool ok[maxn*2];
void ins(int i,int l,int r,int x,int y,int k)
{
if (x<=l && y>=r) cov[i]+=k;
else
{
int mid=(l+r)/2;
if (x<mid) ins(i*2,l,mid,x,y,k);
if (y>mid) ins(i*2+1,mid,r,x,y,k);
}
if (cov[i]>0)
{
num[i]=1;
lcov[i]=rcov[i]=true;
}
else if (l+1==r)
{
num[i]=0;
lcov[i]=rcov[i]=false;
}
else
{
lcov[i]=lcov[i*2];rcov[i]=rcov[i*2+1];
num[i]=num[i*2]+num[i*2+1]-lcov[i*2+1]*rcov[i*2];
}
if (cov[i]>0) sum[i]=r-l;
else if (l+1==r) sum[i]=0;
else sum[i]=sum[i*2]+sum[i*2+1];
}
bool cmp(node a,node b)
{
return a.x<b.x;
}
int main()
{
freopen("pin.txt","r",stdin);
freopen("pou.txt","w",stdout);
int i,j,k;
scanf("%d",&n);
for (i=1;i<=n;i++)
{
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1+=10000;x2+=10000;y1+=10000;y2+=10000;
a[++tot].x=x1;a[tot].y1=y1;a[tot].y2=y2;a[tot].kk=1;
a[++tot].x=x2;a[tot].y1=y1;a[tot].y2=y2;a[tot].kk=-1;
maxy=max(maxy,y2);
}
sort(a+1,a+tot+1,cmp);
ins(1,0,maxy,a[1].y1,a[1].y2,a[1].kk);
int last=0;
for (i=2;i<=tot;i++)
{
ans+=abs(sum[1]-last); //对于竖边
ans+=num[1]*(a[i].x-a[i-1].x)*2; //对于横边
last=sum[1];
ins(1,0,maxy,a[i].y1,a[i].y2,a[i].kk);
}
ans+=abs(sum[1]-last);
cout << ans << endl;
return 0;
}