#include<bits/stdc++.h> using namespace std; #define ll long long const int maxn=1010; int n; double X[maxn<<1]; struct Edge{ double l,r,h; int v; Edge(){}; Edge(double a,double b,double c,int d):l(a),r(b),h(c),v(d){}; bool operator<(const Edge &b)const{ if(h==b.h)return v>b.v; return h<b.h; } }edge[maxn<<1]; struct node{ int l,r,cnt; double s,ss; }ST[maxn<<3]; void build(int l,int r,int rt){ ST[rt].l=l;ST[rt].r=r; ST[rt].cnt=ST[rt].s=ST[rt].ss=0; if(l==r)return; int m=l+r>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); } void cal(int l,int r,int rt){ if(ST[rt].cnt){ ST[rt].s=X[r+1]-X[l]; }else if(ST[rt].l==ST[rt].r){ ST[rt].s=0; }else{ ST[rt].s=ST[rt<<1].s+ST[rt<<1|1].s; } /// if(ST[rt].cnt>1){ ST[rt].ss=X[r+1]-X[l]; }else if(l==r){ ST[rt].ss=0; }else if(ST[rt].cnt==1){ ST[rt].ss=ST[rt<<1].s+ST[rt<<1|1].s; }else{ ST[rt].ss=ST[rt<<1].ss+ST[rt<<1|1].ss; } } void update(int a,int b,int v,int l,int r,int rt){ if(a<=l&&b>=r){ ST[rt].cnt+=v; cal(l,r,rt); return; } int m=l+r>>1; if(a<=m)update(a,b,v,l,m,rt<<1); if(b>m)update(a,b,v,m+1,r,rt<<1|1); cal(l,r,rt); } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); int tt=0; for(int i=1;i<=n;i++){ double x1,x2,y1,y2; scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2); X[++tt]=x1; edge[tt]=Edge(x1,x2,y1,1); X[++tt]=x2; edge[tt]=Edge(x1,x2,y2,-1); } sort(X+1,X+tt+1); sort(edge+1,edge+tt+1); int m=1; for(int i=2;i<=tt;i++){ if(X[i]!=X[i-1])X[++m]=X[i]; } build(1,m,1); double ans=0; for(int i=1;i<tt;i++){ int l=lower_bound(X+1,X+m+1,edge[i].l)-X; int r=lower_bound(X+1,X+m+1,edge[i].r)-X-1; update(l,r,edge[i].v,1,m,1); ans+=ST[1].ss*(edge[i+1].h-edge[i].h); } printf("%.2lf ",ans); } }
大部分代码风格能和扫描线保持一致还蛮开心的。。
多次覆盖的核心就在于cal函数
若当前区间被覆盖过一次,当前区间被覆盖2次的长度就加上子节点们覆盖1次的长度
当时听学长讲的时候还感觉很迷,当时光听,没分清楚覆盖次数和覆盖长度。。orz
估计判AC的时候给了eps吧。。不然我样例都没过啊(