扫描线

线段树维护扫描线的长度--求矩形面积

https://www.luogu.com.cn/record/83280051

注意的就是(1)线段树一个节点代表单位线段,tot不加进去(2)懒度标记优化,用sum记录整条线段的覆盖次数,有就让len=sum_len,没有就用儿子的(3)lenth=M[r+1]-M[l],因为一条线段i的长度是M[i+1]-M[i]

int n,cnt,M[MAXN<<1];
struct Line
{
	ll l,r,h;
	int mark;
	bool operator<(const Line&gh)const
	{
		return h<gh.h;
	}
	Line(){}
	Line(ll wc1,ll wc2,ll wc3,int mar)
	{
		l=wc1,r=wc2,h=wc3;mark=mar;
	}
}e[MAXN<<1];
struct Segtree
{
	int ls,rs,sum;ll len;
}t[MAXN<<2];
int root,tot ;
#define lson t[rt].ls
#define rson t[rt].rs
inline void Build(int&rt,int l,int r)
{
	if(!rt)rt=++tot;
	if(l==r)return;
	int mid=(l+r)>>1;
	Build(lson,l,mid);Build(rson,mid+1,r);
}
inline void Pushup(int rt,int l,int r)
{
	if(t[rt].sum)
	{
		t[rt].len=M[r+1]-M[l];
	}
	else
	{
		t[rt].len=t[lson].len+t[rson].len;
	}
}
inline void Insert(int rt,int l,int r,int L,int R,int mak)
{
	if(R<=M[l]||L>=M[r+1])return;//没关系
	if(L<=M[l]&&M[r+1]<=R)
	{
		t[rt].sum+=mak;
		Pushup(rt,l,r);return;
	}
	int mid=(l+r)>>1;
	Insert(lson,l,mid,L,R,mak);
	Insert(rson,mid+1,r,L,R,mak);
	Pushup(rt,l,r);
}
int main()
{
 	//freopen("A_big_sample.in","r",stdin);
	// freopen("dfs.txt","w",stdout);
	n=re();
	_f(i,1,n)
	{
		ll w1=re(),w2=re(),w3=re(),w4=re();//x1 y1 x2 y2
		e[i<<1]=Line(w1,w3,w2,1);
		e[(i<<1)-1]=Line(w1,w3,w4,-1);
		M[++cnt]=w1,M[++cnt]=w3;
	}
	n<<=1;
	sort(e+1,e+1+n);
	sort(M+1,M+1+cnt);
	int num=unique(M+1,M+1+cnt)-M-1;
	Build(root,1,num-1);//是说忽略掉num+1,因为是线段
	ll sd=0;
	_f(i,1,n-1)//代表线段
	{
		//chu("insert():%lld--%lld\n",e[i].l,e[i].r);
		Insert(root,1,num-1,e[i].l,e[i].r,e[i].mark);
		sd+=(t[root].len)*(e[i+1].h-e[i].h);
	}
	chu("%lld",sd);
    return 0;
}

求周长:我怎么就没想到,就是你横着算一次,竖着算一次。还是维护覆盖的长度,每次相邻的操作之间矩形增加/减少的长度就是矩形增加的周长(真的是,很神奇!但是就是对的)

posted on 2022-08-10 22:11  HZOI-曹蓉  阅读(25)  评论(0编辑  收藏  举报