我们先从hdu 1542开始http://acm.hdu.edu.cn/showproblem.php?pid=1542
这里我们先把每个矩阵的点的y轴坐标,进行一个排序,然后通过排序以后的坐标建一颗线段树。对于每个条超元线段,我们给定一个cover值,表示插入了多少根线段。然后,在把所有与y轴平行的那些线段,我们给定一个flag,标记这是属于矩阵左边(1)还是右边(-1)的线段。从左往右插入线段树。访问到了一条超元线段时(node中的flag标记当前线段是否为超元线段),判断cover是否大于0,如果是,就计算面积,不是则加上线段的flag值。
代码如下:
#include<iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Line { double x; double y1; double y2; int flag; }; struct node { double x; int c; double s; double e; int f; double len; int cover; }; double yc[2000]; Line m[2000]; bool cmp(Line a,Line b) { return a.x < b.x; } node tr[1000000]; void build_tree(int c,int s,int e) { tr[c].x=-1; tr[c].s=yc[s]; tr[c].e=yc[e]; tr[c].len=yc[e]-yc[s]; tr[c].f=0; tr[c].cover=0; if (s+1 >= e) { tr[c].f=1; return ; } build_tree(c<<1,s,(s+e)>>1); build_tree(c<<1 |1,(s+e)>>1,e); return ; } double update(int c,double x,double s,double e,int flag) { if (e <= tr[c].s || s >= tr[c].e) return 0; if (tr[c].f == 1) { if (tr[c].cover > 0) { double t=tr[c].x; tr[c].x=x; tr[c].cover+=flag; return (x-t)*tr[c].len; } else { tr[c].cover+=flag; tr[c].x=x; return 0; } } return update(c<<1,x,s,e,flag)+update(c<<1 |1,x,s,e,flag); } int main() { int n,lyc,i,k; double x1,x2,y1,y2,ans; k=0; while (1) { scanf("%d",&n); if (n == 0) break; lyc=0; for (i=0; i<n; i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); m[lyc].x=x1; m[lyc].y1=y1; m[lyc].y2=y2; m[lyc].flag=1; yc[lyc++]=y1; m[lyc].x=x2; m[lyc].y1=y1; m[lyc].y2=y2; m[lyc].flag=-1; yc[lyc++]=y2; } sort(yc,yc+lyc); sort(m,m+lyc,cmp); build_tree(1,0,lyc-1); ans=0; for (i=0; i<lyc; i++) { ans+=update(1,m[i].x,m[i].y1,m[i].y2,m[i].flag); } printf("Test case #%d\nTotal explored area: %.2f\n\n", ++k, ans); } }
接下来的hdu 1255http://acm.hdu.edu.cn/showproblem.php?pid=1255
如果会求面积并的话,面积交就不是问题了。只需要将原先判断线段树中cover值为大于等于1改为大于等于2即可!
#include<iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Line { double x; double y1; double y2; int flag; }; struct node { double x; int c; double s; double e; int f; double len; int cover; }; double yc[20000]; Line m[20000]; bool cmp(Line a,Line b) { return a.x < b.x; } node tr[10000000]; void build_tree(int c,int s,int e) { tr[c].x=-1; tr[c].s=yc[s]; tr[c].e=yc[e]; tr[c].len=yc[e]-yc[s]; tr[c].f=0; tr[c].cover=0; if (s+1 >= e) { tr[c].f=1; return ; } build_tree(c<<1,s,(s+e)>>1); build_tree(c<<1 |1,(s+e)>>1,e); return ; } double update(int c,double x,double s,double e,int flag) { if (e <= tr[c].s || s >= tr[c].e) return 0; if (tr[c].f == 1) { if (tr[c].cover >= 2) { double t=tr[c].x; tr[c].x=x; tr[c].cover+=flag; return (x-t)*tr[c].len; } else { tr[c].cover+=flag; tr[c].x=x; return 0; } } return update(c<<1,x,s,e,flag)+update(c<<1 |1,x,s,e,flag); } int main() { int n,lyc,i,k,T; double x1,x2,y1,y2,ans; k=0; scanf("%d",&T); while (T--) { scanf("%d",&n); lyc=0; for (i=0; i<n; i++) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); m[lyc].x=x1; m[lyc].y1=y1; m[lyc].y2=y2; m[lyc].flag=1; yc[lyc++]=y1; m[lyc].x=x2; m[lyc].y1=y1; m[lyc].y2=y2; m[lyc].flag=-1; yc[lyc++]=y2; } sort(yc,yc+lyc); sort(m,m+lyc,cmp); build_tree(1,0,lyc-1); ans=0; for (i=0; i<lyc; i++) { ans+=update(1,m[i].x,m[i].y1,m[i].y2,m[i].flag); } printf("%.2f\n",ans); } return 0; }
hdu 1828 http://acm.hdu.edu.cn/showproblem.php?pid=1828
分衡量和纵向两次分别求出横向部分的周长以及纵向部分的周长,然后相加就得到结果。
这道题数据比较弱,没有出两条线段覆盖的情况,所以这种解法能ac。
#include<iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct Line { int x; int y1; int y2; int flag; }; struct node { int c; int s; int e; int f; int len; int cover; }; int yc[20000],zg[20000]; Line m[20000],l[20000]; bool cmp(Line a,Line b) { return a.x < b.x; } node tr[10000000]; void build_tree1(int c,int s,int e) { tr[c].s=yc[s]; tr[c].e=yc[e]; tr[c].len=yc[e]-yc[s]; tr[c].f=0; tr[c].cover=0; if (s+1 >= e) { tr[c].f=1; return ; } build_tree1(c<<1,s,(s+e)>>1); build_tree1(c<<1 |1,(s+e)>>1,e); return ; } void build_tree2(int c,int s,int e) { tr[c].s=zg[s]; tr[c].e=zg[e]; tr[c].len=zg[e]-zg[s]; tr[c].f=0; tr[c].cover=0; if (s+1 >= e) { tr[c].f=1; return ; } build_tree2(c<<1,s,(s+e)>>1); build_tree2(c<<1 |1,(s+e)>>1,e); return ; } double update(int c,double x,double s,double e,int flag) { if (e <= tr[c].s || s >= tr[c].e) return 0; if (tr[c].f == 1) { if (tr[c].cover == 0 || tr[c].cover+flag == 0) { tr[c].cover+=flag; return tr[c].len; } else { tr[c].cover+=flag; return 0; } } return update(c<<1,x,s,e,flag)+update(c<<1 |1,x,s,e,flag); } int main() { int n,lyc,i,k,T; int x1,x2,y1,y2,ans; while (scanf("%d",&n) != EOF) { lyc=0; for (i=0; i<n; i++) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); m[lyc].x=x1; m[lyc].y1=y1; m[lyc].y2=y2; m[lyc].flag=1; l[lyc].y1=x1; l[lyc].y2=x2; l[lyc].x=y1; l[lyc].flag=1; zg[lyc]=x1; yc[lyc++]=y1; m[lyc].x=x2; m[lyc].y1=y1; m[lyc].y2=y2; m[lyc].flag=-1; l[lyc].y1=x1; l[lyc].y2=x2; l[lyc].x=y2; l[lyc].flag=-1; zg[lyc]=x2; yc[lyc++]=y2; } sort(yc,yc+lyc); sort(zg,zg+lyc); sort(l,l+lyc,cmp); sort(m,m+lyc,cmp); ans=0; build_tree1(1,0,lyc-1); for (i=0; i<lyc; i++) { ans+=update(1,m[i].x,m[i].y1,m[i].y2,m[i].flag); } build_tree2(1,0,lyc-1); for (i=0; i<lyc; i++) { ans+=update(1,l[i].x,l[i].y1,l[i].y2,l[i].flag); } printf("%d\n",ans); } return 0; }