数据结构:线段树——扫描线模板

/*
矩形面积
*/
#include <bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
#define ls (rt<<1)
#define rs (rt<<1|1)
const int N=1e5+5;
typedef long long ll;

struct _line{
    int xl,xr,h,f;
    _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; }
}l[N<<1];

int n,xl,yl,xr,yr;
int x[N<<1]; 
int tag[N<<3]; 
ll len[N<<3];
ll ans;

void push_up(int rt,int l,int r){
	if(tag[rt]!=0){
		len[rt]=x[r+1]-x[l];
	}
	else{
		if(l==r) len[rt]=0;
		else len[rt]=len[ls]+len[rs];
	}
}

void modify(int rt,int l,int r,int xl,int xr,int d){
    if(xl<=l&&r<=xr){
    	tag[rt]+=d;
//        len[rt]=(tag[rt]+=d)?x[r+1]-x[l]:0;
		push_up(rt,l,r);
        return ;
    }
    if(xl<=mid) modify(ls,l,mid,xl,xr,d);
    if(xr>mid) modify(rs,mid+1,r,xl,xr,d);
    push_up(rt,l,r);
}

int search_(int xx,int yy,int des){
	int l=xx,r=yy;
	int m;
	while(l<=r){
		m=(l+r)>>1;
		if(des<=x[m]){
			r=m-1;
		}
		else l=m+1;
	}
	return l;
}

int main(void){
    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;
    for(int i=1;i<=2*n;i++){
//    	int xl=search_(1,ct,l[i].xl);
//		int xr=search_(1,ct,l[i].xr);
        int xl=lower_bound(x+1,x+ct+1,l[i].xl)-x;
        // 待修改区间 [xl,xr] -> [xl,xr-1]
        int xr=lower_bound(x+1,x+ct+1,l[i].xr)-x;
        cout<<"xl="<<xl<<"xr="<<xr<<endl;
        // 先算面积,再修改
        ans+=len[1]*(l[i].h-l[i-1].h);
        modify(1,1,ct-1,xl,xr-1,l[i].f);
    }
    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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值