数据结构:线段树——扫描线模板(面积并,周长和)

点击查看折叠代码块
/*
矩形面积
*/
#include <bits/stdc++.h>

#define ed end()
#define bg begin()
#define mkp make_pair
#define pb push_back
#define v(T) vector<T>
#define all(x) x.bg,x.ed
#define newline puts("")
#define si(x) ((int)x.size())
#define rep(i,n) for(int i=1;i<=n;++i)
#define rrep(i,n) for(int i=0;i<n;++i)
#define srep(i,s,t) for(int i=s;i<=t;++i)

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 1e5+10;
const int inf = 0x7f7f7f7f;
const ll inf_ll = 1ll*inf*inf;
const int Mod = 1e9+7;
const double eps = 1e-7;


struct _line{//从下往上扫
    int xl,xr,h,f;//xl扫描线的左端点,xr右端点,h线所在的纵坐标位置,f标记:是矩形的下边(1)还是上边(-1)
    _line(int a=0,int b=0,int c=0,int d=0):xl(a),xr(b),h(c),f(d){}
    bool operator <(const _line &t) const{ return h<t.h; }//按照y的从小到大排序
}L[maxn<<1];

int n,xl,yl,xr,yr;
int x[maxn<<1]; //横坐标离散化
int lazy[maxn<<3];
ll tree[maxn<<3];
ll ans = 0;

void pushup(int l,int r,int rt){
	if(lazy[rt]!=0){//表示被覆盖过
		tree[rt]=x[r+1]-x[l];//更新区间长度
	}
	else{
        if(l == r) tree[rt] = 0;//这里需要注意,如果区间长度为1,不用合并
		else tree[rt]=tree[rt<<1]+tree[rt<<1|1];//合并儿子信息
	}
}

void build(int l,int r,int rt){
    lazy[rt] = 0;
    tree[rt] = 0;
    if( l == r ){
        return ;
    }
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
}

void update(int L,int R,int v,int l,int r,int rt){
    if(L<=l && r<=R){
        lazy[rt]+=v;
        pushup(l,r,rt);
        return ;
    }
    int m=(l+r)>>1;
    if(L<=m) update(L,R,v,l,m,rt<<1);
    if(R>m) update(L,R,v,m+1,r,rt<<1|1);
    pushup(l,r,rt);
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
    	scanf("%d%d%d%d",&xl,&yl,&xr,&yr);
        x[(i<<1)-1]=xl;
		x[i<<1]=xr;
        L[(i<<1)-1]=_line(xl,xr,yl,1);//矩形的下边
		L[i<<1]=_line(xl,xr,yr,-1);//矩形的上边
    }
    sort(x+1,x+2*n+1);//离散化
	sort(L+1,L+2*n+1);

    // 总的区间 [1,ct] -> [1,ct-1]
    int ct=unique(x+1,x+2*n+1)-x-1;//去重,ct的个数表示横坐标的个数

    build(1,ct-1,1);//建树
    ans = 0;
    for (int i=1;i<=2*n;i++){
        // 待修改区间 [l,r] -> [l,r-1]
        int l = lower_bound(x+1,x+ct+1,L[i].xl)-x;
        int r = lower_bound(x+1,x+ct+1,L[i].xr)-x;
        
        ans+=1ll*tree[1]*(L[i].h-L[i-1].h);//先算面积,再修改
        update(l,r-1,L[i].f,1,ct-1,1);
    }
    printf("%lld\n",ans);
    return 0;
}
/*
矩形周长和
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
int n;
int xl,yl,xr,yr;

struct Tree{
	int sum;//区间被线段完全覆盖过几次 
	int num;//区间被多少条不相交的线段覆盖(比如,[1,2],[4,5]则为2,[1,3],[4,5]则为1(我习惯用闭区间),[1,4],[2,2],[4,4]也为1)
	int len;//区间被覆盖的长度
	int lflag;//区间左端点是否被覆盖
	int rflag;//区间右端点是否被覆盖
}tree[maxn<<1];

struct _Line{
	int h;//扫描线的高度
	int l,r;//扫描线的左右端点位置
	int flag;//出边或者入边标记 
	_Line(int a=0,int b=0,int c=0,int d=0):l(a),r(b),h(c),flag(d){}
	bool operator < (const _Line &rhs) const {
		if(h==rhs.h) return flag>rhs.flag;
		else return h<rhs.h;
	}
}L[maxn<<1];

void pushup(int l,int r,int rt){
	if(tree[rt].sum){//区间被完全覆盖过 
		tree[rt].num=1;
		tree[rt].len=r-l+1;
		tree[rt].lflag=tree[rt].rflag=1;
	}
	else{//tree[rt].sum=0
		if(l==r){//叶子结点
			tree[rt].num=0;
			tree[rt].len=0;
			tree[rt].lflag=tree[rt].rflag=0;
		}
		else{//一般情况
			tree[rt].num=tree[rt<<1].num+tree[rt<<1|1].num;
			tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len;
			if(tree[rt<<1].rflag && tree[rt<<1|1].lflag) tree[rt].num--;
			tree[rt].lflag=tree[rt<<1].lflag;
			tree[rt].rflag=tree[rt<<1|1].rflag;
		}
	}
}

void update(int v,int L,int R,int l,int r,int rt){
	if(L<=l && r<=R){
		tree[rt].sum+=v;
		pushup(l,r,rt);
		return ;
	}
	int m=(l+r)>>1;
	if(L<=m) update(v,L,R,l,m,rt<<1);
	if(R>m) update(v,L,R,m+1,r,rt<<1|1);
	pushup(l,r,rt);
}
int X[maxn];
int main(){
	int xmax=-inf,xmin=inf;
	while(~scanf("%d",&n)){
		for (int i=1;i<=n;i++){
			scanf("%d%d%d%d",&xl,&yl,&xr,&yr);
			xmax=max(xmax,max(xl,xr));
			xmin=min(xmin,min(xl,xr));
			L[i*2-1]=_Line(xl,xr,yl,1);
			L[i*2]=_Line(xl,xr,yr,-1);
		}

		if(xmin<=0){//最左边值小于等于0 
			for (int i=1;i<=n*2;i++){
				L[i].l=L[i].l+(-xmin)+1;
				L[i].r=L[i].r+(-xmin)+1;
			}
			xmax+=(-xmin);
		}
		sort(L+1,L+n*2+1);
		
		int ans=0,pre=0;
		for (int i=1;i<=2*n;i++){
			update(L[i].flag,L[i].l,L[i].r-1,1,xmax,1);
			ans+=abs(tree[1].len-pre);
			pre=tree[1].len;
			ans+=tree[1].num*2*(L[i+1].h-L[i].h);
		}
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2020-07-28 19:56  wsl_lld  阅读(104)  评论(0编辑  收藏  举报