【USACO5.5.1】Picture矩形周长
Description
N(N<5000) 张矩形的海报,照片和其他同样形状的图片贴在墙上。它们的边都是垂直的或水平的。每个矩形可以部分或者全部覆盖其他矩形。所有的矩形组成的集合的轮廓称为周长。写一个程序计算周长。
图 1 是一个有 7 个矩形的例子:
图 1.一个 7 个矩形的集合
对应的轮廓为图 2 所示的所有线段的集合:
图 2. 矩形集合的轮廓
所有矩形的顶点坐标均为整数。所有的坐标都在 [-10000,10000] 的范围内,并且任何一个矩形面积都为整数。结果的值可能需要 32 位有符号整数表示。
Input
第1行: N,张贴在墙上的矩形的数目。 第 2..N+1行 接下来的N行中,每行都有两个点的坐标,分别是矩形的左下角坐标和右上角坐标。每一个坐标由 X 坐标和 Y 坐标组成。
Output
只有一行,为一个非负整数,表示输入数据中所有矩形集合的轮廓长度。
Sample Input
7
-15 0 5 10
-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
30 10 36 20
34 0 40 16
Sample Output
228
分析:
1.每个矩形由两条横向边和两条纵向边组成。
2.对于横向边,按纵坐标排序。设当前讨论的边为 A [s , t]
如果A是某个矩形的靠下的边,在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加
(t-s-x);
如果A是某个矩形的靠上的边,先删除它的对应边,再在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加
(t-s-x);
3、对于纵向边,按横坐标排序,讨论方法与横向边相同。
注意建树方式是以单位线段为叶子节点
代码如下:
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#define LL long long
#define CLEAR(xxx) memset(xxx,0,sizeof(xxx))
using namespace std;
const int maxn=20000+5,inf=1e9;
int n,m,ans=0;
inline void _read(int &x){
char ch=getchar(); bool mark=false;
for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;
for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
if(mark)x=-x;
}
struct segment{
int s,t,p,id; //s,t为线段的端点,p是排序的依据,id是排序前的编号。
segment(int a,int b,int c,int d):s(a),t(b),p(c),id(d){}
segment(){s=t=p=id=0;}
bool operator <(const segment a) const {
return p<a.p;
}
};
segment x[maxn],y[maxn];
int lazy[maxn<<4],cnt[maxn<<4],l,r;
// cnt 表示区间被覆盖的次数,cnt[o]>0表示区间o被覆盖
void pushdown(int o){
int ls=o<<1,rs=ls+1;
lazy[ls]+=lazy[o];
cnt[ls]+=lazy[o];
cnt[rs]+=lazy[o];
lazy[rs]+=lazy[o];
lazy[o]=0;
}
void update(int o,int L,int R,int delta){
if(lazy[o]) pushdown(o);
if(l<=L&&r>=R){
cnt[o]+=delta;
lazy[o]+=delta;
}
else if(L+1<R){
int mid=(L+R)>>1,ls=o<<1,rs=ls+1;
if(l<=mid&&L<=r) update(ls,L,mid,delta);
if(r>=mid&&l<=R) update(rs,mid,R,delta);
}
}
int query(int o,int L,int R){
if(lazy[o]) pushdown(o);
if(l<=L&&r>=R&&cnt[o]>0) return R-L; //被查询的区间完全包含,且被覆盖
if(L+1<R){
int mid=(L+R)>>1,a=0,b=0;
if(l<=mid)a=query(o<<1,L,mid);
if(r>=mid)b=query(o*2+1,mid,R);
return a+b;
}
return 0;
}
int main(){
int i,j,x1,x2,y1,y2;
_read(n);
for(i=1;i<=n;i++){
_read(x1); _read(y1) ;_read(x2) ;_read(y2);
x1+=10001; x2+=10001; //注意将坐标全部变为正数
y1+=10001; y2+=10001;
x[i]=segment(x1,x2,y1,i);
y[i] =segment(y1,y2,x1,i);
x[i+n]=segment(x1,x2,y2,i+n); //编号为 n+1 ~ 2*n的是矩形的后一条边
y[i+n] =segment(y1,y2,x2,i+n);
}
sort(x+1,x+1+2*n);
sort(y+1,y+1+2*n);
CLEAR(lazy); CLEAR(cnt);
for(i=1;i<=n*2;i++){ //讨论横向边
l=x[i].s; r=x[i].t;
if(x[i].id<=n){
ans+=abs(r-l-query(1,1,maxn));
update(1,1,maxn,1);
}
else {
update(1,1,maxn,-1);
ans+=abs(r-l-query(1,1,maxn) );
}
}
CLEAR(lazy); CLEAR(cnt);
for(i=1;i<=n*2;i++){ //讨论纵向边
l=y[i].s; r=y[i].t;
if(y[i].id<=n){
ans+=abs(r-l-query(1,1,maxn) );
update(1,1,maxn,1);
}
else {
update(1,1,maxn,-1);
ans+=abs(r-l-query(1,1,maxn));
}
}
cout<<ans<<endl;
return 0;
}
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define inf 1e9
using namespace std;
const int maxn=50005;
int n;
struct node{
int a,b;
int cover,lazy;
};
node tree[maxn*4];
struct line{
int a,b,t,num;
line(){}
line(int whore,int postitute,int bastard,int tit){a=whore;b=postitute;t=bastard;num=tit;}
};
line edgex[maxn*10],edgey[maxn*10];
bool cmp(line a,line b){
return a.t<b.t;
}
void build_tree(int p,int x,int y){
tree[p].a=x;tree[p].b=y;
tree[p].lazy=0;tree[p].cover=0;
int mid=(x+y)/2;
if(x+1<y){
build_tree((p<<1),x,mid);
build_tree((p<<1)+1,mid,y);
}
}
void putdown(int p){
//if(tree[p].a+1==tree[p].b)return;
int ls=(p<<1),rs=(p<<1)+1;
tree[ls].lazy+=tree[p].lazy;
tree[rs].lazy+=tree[p].lazy;
tree[ls].cover+=tree[p].lazy;
tree[rs].cover+=tree[p].lazy;
tree[p].lazy=0;
}
int query(int p,int x,int y){
if(x>tree[p].b||y<tree[p].a)return 0;
if(tree[p].lazy)putdown(p);
if(x<=tree[p].a&&tree[p].b<=y&&tree[p].cover>0)return tree[p].b-tree[p].a;
if(tree[p].a+1<tree[p].b){
int t1=query((p<<1),x,y);
int t2=query((p<<1)+1,x,y);
return t1+t2;
}
return 0;
}
void change(int p,int x,int y,int d){
if(x>tree[p].b||y<tree[p].a)return;
if(tree[p].lazy)putdown(p);
if(x<=tree[p].a&&tree[p].b<=y){
tree[p].lazy+=d;
tree[p].cover+=d;
return;
}
change((p<<1),x,y,d);
change((p<<1)+1,x,y,d);
}
int main(){
int i,j,k,ans=0;
cin>>n;
for(i=1;i<=n;i++){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x1+=10001;x2+=10001;y1+=10001;y2+=10001;
edgex[i]=line(x1,x2,y1,i);
edgex[i+n]=line(x1,x2,y2,i+n);
edgey[i]=line(y1,y2,x1,i);
edgey[i+n]=line(y1,y2,x2,i+n);
}
sort(edgex+1,edgex+1+2*n,cmp);
sort(edgey+1,edgey+1+2*n,cmp);
build_tree(1,1,20005);
int temp;
for(i=1;i<=2*n;i++){
if(edgex[i].num<=n){
temp=query(1,edgex[i].a,edgex[i].b);
ans+=abs(edgex[i].b-edgex[i].a-temp);
change(1,edgex[i].a,edgex[i].b,1);
}
else{
temp=query(1,edgex[i].a,edgex[i].b);
change(1,edgex[i].a,edgex[i].b,-1);
ans+=abs(edgex[i].b-edgex[i].a-temp);
}
//cout<<ans<<endl;
}
memset(tree,0,sizeof(tree));
build_tree(1,1,20005);
for(i=1;i<=2*n;i++){
if(edgey[i].num<=n){
temp=query(1,edgey[i].a,edgey[i].b);
ans+=abs(edgey[i].b-edgey[i].a-temp);
change(1,edgey[i].a,edgey[i].b,1);
}
else{
temp=query(1,edgey[i].a,edgey[i].b);
change(1,edgey[i].a,edgey[i].b,-1);
ans+=abs(edgey[i].b-edgey[i].a-temp);
}
//cout<<ans<<endl;
}
cout<<ans*2;
}