链接:POJ-1177 Picture
给出平面直角坐标系上 n n n( 0 ≤ n ≤ 5000 0\le n\le 5000 0≤n≤5000)个矩形,求所有矩形合并后的所有线段长度之和。
以计算 水平线段(平行于 x x x轴)的长度之和 为例,竖直扫描线(平行于 y y y轴)水平扫过 各矩形的 左、右边界;
可以发现,每扫过单位水平长度,水平线段长度之和应当增加 当前竖直方向的线段数目 ∗ 2 *2 ∗2;
故要用线段树维护竖直方向的覆盖线段数目,较为特殊的一点是,虽然是区间修改,但是并不需要下传延迟标记(lazy tag),因为
随后计算 竖直线段(平行于 y y y轴)的长度之和 ,做相同处理即可;
此外,要先对数据做离散化处理,不再用坐标,而是用第几号线段至第几号线段来表示边界,更便于处理,详见代码。
#include
#define lowbit(x) ((x)&(-(x)))
using namespace std;
typedef long long LL;
const int INF=0x3f3f3f3f;
const int maxn=1e4+10;
int n,X[maxn],N,Y[maxn],M;
struct rectangle
{
int a,b,c,d;
}r[maxn];
struct border
{
int l,r; //该边界由线段l~r组成
bool tag; //tag=1,左边界/下边界;tag=0,右边界/上边界
};
vector<border> x[maxn],y[maxn];
void prework() //离散化
{
sort(X+1,X+N+1);
sort(Y+1,Y+M+1);
N=unique(X+1,X+N+1)-(X+1);
M=unique(Y+1,Y+M+1)-(Y+1);
for(int i=1;i<=n;i++)
{
r[i].a=lower_bound(X+1,X+N+1,r[i].a)-X;
r[i].c=lower_bound(X+1,X+N+1,r[i].c)-X;
r[i].b=lower_bound(Y+1,Y+M+1,r[i].b)-Y;
r[i].d=lower_bound(Y+1,Y+M+1,r[i].d)-Y;
x[r[i].a].push_back(border{r[i].b,r[i].d-1,1});
x[r[i].c].push_back(border{r[i].b,r[i].d-1,0});
y[r[i].b].push_back(border{r[i].a,r[i].c-1,1});
y[r[i].d].push_back(border{r[i].a,r[i].c-1,0});
}
}
struct node
{
int num; //该区间包含的线段数
int cnt; //该区间被直接整体覆盖的次数(相当于不下传的延迟标记)
int ltag; //该区间最左端有无被覆盖
int rtag; //该区间最右端有无被覆盖
}t[maxn<<2];
void push_up(int rt)
{
if(t[rt].cnt>0) //该区间被直接整体覆盖
{
t[rt].num=1;
t[rt].ltag=t[rt].rtag=1;
}
else //未被直接整体覆盖
{
t[rt].num=t[rt<<1].num+t[rt<<1|1].num; //左子树线段数+右子树线段数
if(t[rt<<1].rtag&&t[rt<<1|1].ltag)
t[rt].num--;
t[rt].ltag=t[rt<<1].ltag;
t[rt].rtag=t[rt<<1|1].rtag;
}
}
void updata(int rt,int l,int r,int ql,int qr,int op) //op=1:增加矩阵
{ //op=0:删除矩阵
if(ql<=l&&r<=qr)
{
if(op)
t[rt].cnt++;
else
t[rt].cnt--;
push_up(rt);
return;
}
int mid=(l+r)>>1;
if(ql<=mid)
updata(rt<<1,l,mid,ql,qr,op);
if(qr>mid)
updata(rt<<1|1,mid+1,r,ql,qr,op);
push_up(rt);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d %d %d",&r[i].a,&r[i].b,&r[i].c,&r[i].d);
X[++N]=r[i].a;X[++N]=r[i].c;
Y[++M]=r[i].b;Y[++M]=r[i].d;
}
prework();
int ans=0;
for(int i=1;i<=N;i++)
{
if(i>1)
ans+=(X[i]-X[i-1])*(t[1].num*2);
for(auto b:x[i])
updata(1,1,M-1,b.l,b.r,b.tag);
}
memset(t,0,sizeof(t));
for(int i=1;i<=M;i++)
{
if(i>1)
ans+=(Y[i]-Y[i-1])*(t[1].num*2);
for(auto b:y[i])
updata(1,1,N-1,b.l,b.r,b.tag);
}
printf("%d\n",ans);
return 0;
}