我们先从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;
}