hdu1828 线段树+扫描线计算矩形周长并
hdu1828 Picture
传送门
题意
平面上有\(n(0\leq n < 5000)\)个矩形,每个矩形左下角坐标为\((x_1,y_1)\),右上角坐标为\((x_2,y_2)\),坐标的值是位于\([-10000,10000]\)之中内的整数,计算矩形周长并。
题解
方法一
两次扫描线
使用计算矩形面积并中,线段树+扫描线的方法,离散化一维坐标,从下向上,从左向右做两次扫描线,分别计算横边和竖边的总长度
当前增加的长度等于当前的总长度与上一次的总长度之差的绝对值
ps. G++返回WA,C++能过
#include<iostream>
#include<cstdio>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLI pair<LL,int>
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define lowbit(x) (x&(-x))
using namespace std;
const int maxn=5010;
int n,m1,m2,k1,k2,X[2*maxn],Y[2*maxn];
struct node{
int l,r,h,state;
node(){}
node(int l,int r,int h,int state):l(l),r(r),h(h),state(state){}
bool operator < (const node& t) const{
return h<t.h;
}
}nodes1[2*maxn],nodes2[2*maxn];
struct SGT{
int cnt,sum;
}sgt[8*maxn];
int binary_search(int x,int num,int* a){
int l=1,r=num;
while(r>=l){
int mid=(l+r)>>1;
if(a[mid]==x) return mid;
if(a[mid]>x) r=mid-1;
else l=mid+1;
}
return -1;
}
void pushup(int o,int l,int r,int* a){
if(sgt[o].cnt) sgt[o].sum=a[r+1]-a[l];
else if(l==r) sgt[o].sum=0;
else sgt[o].sum=sgt[o<<1].sum+sgt[o<<1|1].sum;
}
void build(int o,int l,int r){
sgt[o].cnt=sgt[o].sum=0;
if(l==r) return;
int mid=(l+r)>>1;
build(lson);
build(rson);
}
void update(int o,int l,int r,int ql,int qr,int v,int* a){
if(ql<=l && r<=qr){
sgt[o].cnt+=v;
pushup(o,l,r,a);
return;
}
int mid=(l+r)>>1;
if(ql<=mid) update(lson,ql,qr,v,a);
if(qr>mid) update(rson,ql,qr,v,a);
pushup(o,l,r,a);
}
int main(){
while(scanf("%d",&n)!=EOF){
m1=m2=0;
for(int i=1;i<=n;i++){
int x11,y11,x22,y22;
scanf("%d %d %d %d",&x11,&y11,&x22,&y22);
++m1;
nodes1[m1]=node(x11,x22,y11,1);
X[m1]=x11;
++m1;
nodes1[m1]=node(x11,x22,y22,-1);
X[m1]=x22;
++m2;
nodes2[m2]=node(y11,y22,x11,1);
Y[m2]=y11;
++m2;
nodes2[m2]=node(y11,y22,x22,-1);
Y[m2]=y22;
}
sort(nodes1+1,nodes1+1+m1);
sort(nodes2+1,nodes2+1+m2);
sort(X+1,X+1+m1);
sort(Y+1,Y+1+m2);
k1=k2=1;
for(int i=2;i<=m1;i++){
if(X[i]!=X[i-1]) X[++k1]=X[i];
}
for(int i=2;i<=m2;i++){
if(Y[i]!=Y[i-1]) Y[++k2]=Y[i];
}
int ans=0,last=0;
build(1,1,k1-1);
for(int i=1;i<=m1;i++){
int l=binary_search(nodes1[i].l,k1,X);
int r=binary_search(nodes1[i].r,k1,X)-1;
update(1,1,k1-1,l,r,nodes1[i].state,X);
ans+=abs(sgt[1].sum-last);
last=sgt[1].sum;
}
last=0;
build(1,1,k2-1);
for(int i=1;i<=m2;i++){
int l=binary_search(nodes2[i].l,k2,Y);
int r=binary_search(nodes2[i].r,k2,Y)-1;
update(1,1,k2-1,l,r,nodes2[i].state,Y);
ans+=abs(sgt[1].sum-last);
last=sgt[1].sum;
}
printf("%d\n",ans);
}
}
方法二
一次扫描线
从下向上扫描,横边长度按照两次扫描线的方法计算,同时统计竖边长度
线段树节点中增加三个变量:
num:当前区间内的竖边总数
ls:当前区间的左端点是否被覆盖
rs:当前区间的右端点是否被覆盖
更新方法为:
如果当前区间被完全覆盖,则\(num=2,ls=rs=true\)
否则如果当前为叶节点,则进行初始化:\(num=0,ls=rs=false\)
否则,\(num\)为左儿子和右儿子的\(num\)之和,\(ls\)与左儿子的\(ls\)一致,\(rs\)与右儿子的\(rs\)一致。如果左儿子的\(rs\)和右儿子的\(ls\)均为\(true\),则当前节点\(num-=2\)
当前竖边总长度的计算方法为当前所有竖边的数量(线段树根节点的\(num\)值)乘上当前扫描线和后一条扫描线的高度差
ps. G++,C++都能过
#include<bits/stdc++.h>
#define LL long long
#define PII pair<int,int>
#define PLI pair<LL,int>
#define lson o<<1,l,mid
#define rson o<<1|1,mid+1,r
#define lowbit(x) (x&(-x))
using namespace std;
const int maxn=5010;
int n,m,k,X[2*maxn];
struct node{
int l,r,h,state;
node(){}
node(int l,int r,int h,int state):l(l),r(r),h(h),state(state){}
bool operator < (const node& t)const{
if(h==t.h) return state>t.state;
return h<t.h;
}
}nodes[2*maxn];
struct SGT{
int cnt,sum,num;
bool ls,rs;
}sgt[8*maxn];
int binary_search(int x){
int l=1,r=k;
while(r>=l){
int mid=(l+r)>>1;
if(X[mid]==x) return mid;
if(X[mid]>x) r=mid-1;
else l=mid+1;
}
return -1;
}
void build(int o,int l,int r){
sgt[o].cnt=sgt[o].sum=sgt[o].num=0;
sgt[o].ls=sgt[o].rs=false;
if(l==r) return;
int mid=(l+r)>>1;
build(lson);
build(rson);
}
void pushup(int o,int l,int r){
if(sgt[o].cnt){
sgt[o].sum=X[r+1]-X[l];
sgt[o].num=2;
sgt[o].ls=sgt[o].rs=true;
}
else if(l==r){
sgt[o].sum=sgt[o].num=0;
sgt[o].ls=sgt[o].rs=false;
}
else{
sgt[o].sum=sgt[o<<1].sum+sgt[o<<1|1].sum;
sgt[o].num=sgt[o<<1].num+sgt[o<<1|1].num;
sgt[o].ls=sgt[o<<1].ls;
sgt[o].rs=sgt[o<<1|1].rs;
if(sgt[o<<1].rs && sgt[o<<1|1].ls) sgt[o].num-=2;
}
}
void update(int o,int l,int r,int ql,int qr,int state){
if(ql<=l && r<=qr){
sgt[o].cnt+=state;
pushup(o,l,r);
return;
}
int mid=(l+r)>>1;
if(ql<=mid) update(lson,ql,qr,state);
if(qr>mid) update(rson,ql,qr,state);
pushup(o,l,r);
}
int main(){
while(scanf("%d",&n)!=EOF){
m=0;
for(int i=1;i<=n;i++){
int x11,y11,x22,y22;
scanf("%d %d %d %d",&x11,&y11,&x22,&y22);
++m;
nodes[m]=node(x11,x22,y11,1);
X[m]=x11;
++m;
nodes[m]=node(x11,x22,y22,-1);
X[m]=x22;
}
sort(nodes+1,nodes+1+m);
sort(X+1,X+1+m);
k=1;
for(int i=2;i<=m;i++){
if(X[i]!=X[i-1]) X[++k]=X[i];
}
build(1,1,k-1);
int ans=0,last=0;
for(int i=1;i<=m;i++){
int l=binary_search(nodes[i].l);
int r=binary_search(nodes[i].r)-1;
update(1,1,k-1,l,r,nodes[i].state);
ans+=abs(sgt[1].sum-last);
ans+=sgt[1].num*(nodes[i+1].h-nodes[i].h);
last=sgt[1].sum;
}
printf("%d\n",ans);
}
}