注意点:
- 线段树中使用获取具体长度时右端点应当+1,向线段树内插入值时右端点应当-1.(区间覆盖线段树)
#include<cstdio> #include<iostream> #include<algorithm> #define ll long long using namespace std; const int MAXN=2e6+50; struct Line{ ll x1,x2; ll y; bool type;//0:出现 1:删除 bool operator <(Line another)const{ return y<another.y; } }lines[MAXN]; int lineCnt=0; void addLine(ll x1,ll x2,ll y,bool type){ lines[++lineCnt].x1=x1; lines[lineCnt].x2=x2; lines[lineCnt].y=y; lines[lineCnt].type=type; } struct Node{ int l,r; ll len,cnt;//长度 覆盖次数 }tr[MAXN*4]; int root=1; void build(int p,int l,int r){ tr[p].l=l,tr[p].r=r; if(l==r)return; int mid=(l+r)>>1; build(p<<1,l,mid); build((p<<1)|1,mid+1,r); } ll a[MAXN];//离散化后的x坐标 void pushup(int p){ if(tr[p].cnt){ tr[p].len=a[tr[p].r+1]-a[tr[p].l]; }else{ tr[p].len=tr[p<<1].len+tr[(p<<1)|1].len; } } void change(int p,int l,int r,int val){ if(tr[p].l>=l&&tr[p].r<=r){ tr[p].cnt+=val; pushup(p); return; } int mid=(tr[p].l+tr[p].r)>>1; if(l<=mid)change(p<<1,l,r,val); if(r>mid)change((p<<1)|1,l,r,val); pushup(p); } int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++){ int x1,y1,x2,y2; cin>>x1>>y1>>x2>>y2; a[i]=x1,a[i+n]=x2; addLine(x1,x2,y1,0); addLine(x1,x2,y2,1); } sort(a+1,a+2*n+1); int cnt=unique(a+1,a+2*n+1)-a-1;//离散化 build(root,1,cnt-1); sort(lines+1,lines+lineCnt+1); ll ans=0; for(int i=1;i<=lineCnt;i++){ Line nowLine=lines[i]; if(i>1){ ans+=tr[root].len*(nowLine.y-lines[i-1].y); } if(nowLine.type==0){//增加 change(root,lower_bound(a+1,a+cnt+1,nowLine.x1)-a,lower_bound(a+1,a+cnt+1,nowLine.x2)-a-1,1); }else if(nowLine.type==1){//减少 change(root,lower_bound(a+1,a+cnt+1,nowLine.x1)-a,lower_bound(a+1,a+cnt+1,nowLine.x2)-a-1,-1); } } cout<<ans<<endl; return 0; }