周长并和面积并一样是扫描线法,从下到上扫过去,用len表示当前区间线段长度,那么每次扫描的时候要加上当前的len[1]减去上次的len[1]的绝对值(因为上次的len已经加过了),这是水平方向的。还有竖直方向,用segnum数组维护当前区间的线段共能在竖直方向构成多少条线段(其实就是有当前区间的线段有多少个端点),维护segnum数组还需要两个bool数组lb,rb分别表示当前区间的左端点和右端点是否被线段覆盖,那么segnum[o]=segnum[o<<1]+segnum[o<<1|1],若rb[o<<1]&&lb[o<<1|1],说明两条线段重合了,segnum[o]要减2。
别忘了最后一条边,因为扫描完倒数第二条边后len[1]的长度就是最后一条边的长度,所以最后还要加上len[1]。
因为这道题坐标范围不大,所以可以用线段树表示坐标,也可以像面积并那样先把所有x记下来从小到大排序,每次更新的时候先二分找到坐标的编号,线段树表示的不是真实坐标,而是x的相对坐标,相当于离散化一下。
两种方法的代码:
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define MAXN 10010
#define MAXM 20010
#define MAXNODE 4*MAXN
using namespace std;
int N,M,covered[MAXM<<2],segnum[MAXM<<2],len[MAXM<<2];
bool lb[MAXM<<2],rb[MAXM<<2];
struct Line{
int x1,x2,y,cover;
bool operator < (const Line& x) const{
return y=R) lb[o]=rb[o]=len[o]=segnum[o]=0;
else{
lb[o]=lb[o<<1];
rb[o]=rb[o<<1|1];
len[o]=len[o<<1]+len[o<<1|1];
segnum[o]=segnum[o<<1]+segnum[o<<1|1];
if(rb[o<<1]&&lb[o<<1|1]) segnum[o]-=2;
}
}
void update(int o,int L,int R,int ql,int qr,int cover){
if(ql<=L&&qr>=R){
covered[o]+=cover;
maintain(o,L,R);
return;
}
int mid=(L+R)>>1;
if(qlmid) update(o<<1|1,mid,R,ql,qr,cover);
maintain(o,L,R);
}
int main(){
freopen("in.txt","r",stdin);
while(scanf("%d",&N)!=EOF){
M=0;
int LB=INF,RB=-INF;
while(N--){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
LB=min(LB,x1);
RB=max(RB,x2);
add_line(x1,y1,x2,y2);
}
sort(line,line+M);
for(int i=0;i<(MAXM<<2);i++) lb[i]=rb[i]=covered[i]=segnum[i]=len[i]=0;
int last=0,ans=0;
for(int i=0;i
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
#define MAXN 10010
#define MAXM 10010
#define MAXNODE 4*MAXN
using namespace std;
int N,M,covered[MAXM<<2],segnum[MAXM<<2],len[MAXM<<2],x[MAXN<<1];
bool lb[MAXM<<2],rb[MAXM<<2];
struct Line{
int x1,x2,y,cover;
bool operator < (const Line& x) const{
return y=R) lb[o]=rb[o]=len[o]=segnum[o]=0;
else{
lb[o]=lb[o<<1];
rb[o]=rb[o<<1|1];
len[o]=len[o<<1]+len[o<<1|1];
segnum[o]=segnum[o<<1]+segnum[o<<1|1];
if(rb[o<<1]&&lb[o<<1|1]) segnum[o]-=2;
}
}
void update(int o,int L,int R,int ql,int qr,int cover){
if(ql<=L&&qr>=R){
covered[o]+=cover;
maintain(o,L,R);
return;
}
int mid=(L+R)>>1;
if(qlmid) update(o<<1|1,mid,R,ql,qr,cover);
maintain(o,L,R);
}
int main(){
freopen("in.txt","r",stdin);
while(scanf("%d",&N)!=EOF){
M=0;
int NX=1;
while(N--){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
x[NX++]=x1;
x[NX++]=x2;
add_line(x1,y1,x2,y2);
}
sort(x+1,x+NX);
sort(line,line+M);
NX=unique(x+1,x+NX)-x-1;
for(int i=0;i<(MAXM<<2);i++) lb[i]=rb[i]=covered[i]=segnum[i]=len[i]=0;
int last=0,ans=0;
for(int i=0;i