hdu1255 矩阵的交 线段树+扫描线
/* 不是叶子节点 ,且cnt=1.注意这里,cnt=1确切的意义是什么, 应该是,可以确定,这个区间被完全覆盖了1次, 而有没有被完全覆盖两次或以上则不知道无法确定,那么怎么怎么办了, 只要加上t[lch].s + t[rch].s 即,看看左右孩子区间被覆盖了一次或以上的长度, 那么叠加在双亲上就是双亲被覆盖两次或以上的长度 */ #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define maxn 1005 struct segment { double l,r,h; int f; }s[maxn*2]; struct node { int cnt; double len1;//记录一次及以上的 double len2;//记录二次及以上的 }tree[maxn*8]; double mark[maxn<<1]; bool cmp(segment a,segment b) { return a.h<b.h; } void build(int l,int r,int rt) { tree[rt].cnt=0; tree[rt].len1=tree[rt].len2=0; if(l==r) { return ; } int m=(l+r)/2; build(lson); build(rson); } /* 重点。 若该节点的cnt >= 2,说明被至少两条线段覆盖,那么len1=len2=区间长度。 若该节点的cnt == 1,说明该区间被一条线段覆盖,len1=区间长度,只要左右节点的len1有值, 那么那些长度一定是至少被覆盖两次的,因此len2为左右节点的len1之和。 若该节点的cnt = 0,说明没被完全覆盖,直接用其左右节点更新。 还要注意特判叶子节点。 */ void getlen(int l,int r,int rt) { if(tree[rt].cnt>=2)//>=2时很好理解,就是覆盖2次或以上,直接减一减 { tree[rt].len1=mark[r+1]-mark[l]; tree[rt].len2=mark[r+1]-mark[l]; } else if(tree[rt].cnt==1)//此处需要注意 //由于cnt大于0,所以覆盖一次或以上的部分直接得到,而由于完全覆盖一次 //可能其他部分有覆盖,此时就可以根据左右孩子来,由于len1记录覆盖一次或 //以上的,因为已经完全覆盖了一次,只要加上左右孩子的一次或以上覆盖的值 //那么就是2次或以上覆盖的值。 { tree[rt].len1=mark[r+1]-mark[l];//因为覆盖一次,len1还要继续加 if(l == r)//由于覆盖一次,又只有一个l==r,所以len2为0 { tree[rt].len2=0; } else { tree[rt].len2=tree[rt<<1].len1+tree[rt<<1|1].len1; } } else if(tree[rt].cnt==0)//为完全覆盖,根据孩子来。此处与上面等于1出相似,可以发现,如果为完全覆盖 //就可以根据左右孩子得到覆盖的,那cnt等于1时,要求覆盖2次的时候就也可以 //根据孩子来。 { if(l == r) tree[rt].len1=tree[rt].len2=0; else { tree[rt].len1=tree[rt<<1].len1+tree[rt<<1|1].len1; tree[rt].len2=tree[rt<<1].len2+tree[rt<<1|1].len2; } } } void updata(int L,int R,int c,int l,int r,int rt) { if(l>=L&&R>=r) { tree[rt].cnt+=c; getlen(l,r,rt); return ; } int m=(l+r)/2; if(m>=L) updata(L,R,c,lson); if(R>m) updata(L,R,c,rson); getlen(l,r,rt); } int find(double val,int x,int y) { int l=x,r=y,m; while(l<=r) { m=(l+r)/2; if(mark[m]==val) return m; else if(mark[m]>val) r=m-1; else l=m+1; } return -1; } int main() { int t,n,i; double x1,x2,y1,y2; scanf("%d",&t); while(t--) { scanf("%d",&n); int m=0; for(i=0;i<n;i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); s[m].l=x1;s[m].r=x2;s[m].h=y1;s[m].f=1;mark[m++]=x1; s[m].l=x1;s[m].r=x2;s[m].h=y2;s[m].f=-1;mark[m++]=x2; } sort(s,s+m,cmp); sort(mark,mark+m); int k=1; for(i=1;i<m;i++) { if(mark[i]!=mark[i-1]) mark[k++]=mark[i]; } /* for(i=0;i<k;i++) printf("%.2lf ",mark[i]); printf("\n"); */ build(0,k-1,1); double ans=0; for(i=0;i<m;i++) { int ll=find(s[i].l,0,k-1); int rr=find(s[i].r,0,k-1)-1; updata(ll,rr,s[i].f,0,k-1,1); ans+=(s[i+1].h-s[i].h)*tree[1].len2; } printf("%.2lf\n",ans); } }