扫描线【模板】

发布时间 2023-05-03 09:53:42作者: hewanying

扫描线

用离散线段树实现
时间复杂度\(O(n \log n)\)

P5490 【模板】扫描线

题目描述

代码

#include <bits/stdc++.h>
using namespace std;
#define mid (l+r)/2
#define lson l,mid,rt<<1
#define rson mid,r,rt<<1|1
#define int long long

const int maxn=2e5+10;
int n,y[maxn*2],ans;
struct tree{
  int l,r,len,cnt=0;
}tr[maxn*8];//pushup会多一层 
struct Line{
  int x,y1,y2,flag;
  bool operator <(const Line &rhs) const{
    return x<rhs.x; 
  }
}L[maxn*2];

void pushup(int rt){
  if(tr[rt].cnt>0) tr[rt].len=tr[rt].r-tr[rt].l;
  else tr[rt].len=tr[rt<<1].len+tr[rt<<1|1].len;
}

void build(int l,int r,int rt){
  tr[rt].l=y[l],tr[rt].r=y[r];
  if(r==l+1) return ;//叶子结点长度是2
  build(lson);build(rson); 
}

void update(int rt,int a,int b,int cnt){
  if(a>=tr[rt].r||b<=tr[rt].l) return;
  if(a<=tr[rt].l&&b>=tr[rt].r){
  	tr[rt].cnt+=cnt;pushup(rt);
  	return;
  }
  update(rt<<1,a,b,cnt);update(rt<<1|1,a,b,cnt);
  pushup(rt);
}

signed main(){
  /*2023.5.3 hewanying P5490 【模板】扫描线 扫描线*/ 
  scanf("%lld",&n);
  for(int i=1;i<=n;i++){
  	int X1,X2,Y1,Y2;
  	scanf("%lld%lld%lld%lld",&X1,&Y1,&X2,&Y2);
  	L[i]=(Line){X1,Y1,Y2,1};L[i+n]=(Line){X2,Y1,Y2,-1};
  	y[i]=Y1;y[i+n]=Y2;
  }
  n*=2;
  sort(L+1,L+n+1);sort(y+1,y+n+1);
  build(1,n,1);
  for(int i=1;i<n;i++){
  	update(1,L[i].y1,L[i].y2,L[i].flag);
  	ans+=(L[i+1].x-L[i].x)*tr[1].len;
  }
  printf("%lld\n",ans);
  return 0;
}