hotel的网好差…..
线段树求面积并
HDU 1542
题意:给几个矩形,求总面积,重叠部分只算一次。
分析:可以先看看线段树算法了解扫描线思想.
using namespace std;
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn = 2000;
double xx[maxn];
struct node{
double x1,x2,h;
int t;
}a[maxn];
bool cmp(node a1,node a2){
return a1.hdouble v[maxn<<2];
int flag[maxn<<2];
//不能和之前一样,每个线段树的叶子节点代表一个点,应该代表一段线段,那样的话就不会有几个点分开的样子了
void sert(int i,int l,int r,int L,int R,int t)
{
if(l==L&&r==R){
flag[i]+=t;
if(flag[i]) v[i]=xx[r]-xx[l-1];
else v[i]=0;
return ;
}
int mid = (l+r)>>1;
if(R<=mid) sert(i<<1,l,mid,L,R,t);
else if(L>mid) sert(i<<1|1,mid+1,r,L,R,t);
else {
sert(i<<1,l,mid,L,mid,t);
sert(i<<1|1,mid+1,r,mid+1,R,t);
}
if(!flag[i]) v[i]=v[i<<1]+v[i<<1|1];
}
void update(int i,int l,int r)
{
if(l==r) return ;
int mid = (l+r)>>1;
update(i<<1,l,mid);
update(i<<1|1,mid+1,r);
if(flag[i]) v[i]=xx[r]-xx[l-1];
else v[i]=v[i<<1]+v[i<<1|1];
}
int main()
{
int n,k=0;
while(scanf("%d",&n)!=EOF&&n){
mem(xx,0);mem(a,0);mem(v,0);mem(flag,0);
double x1,x2,y1,y2;
int h2=0,h1=0;
for(int i=1;i<=n;i++){
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
if(y1>y2) swap(y1,y2);
a[h2].x1=x1,a[h2].x2=x2,a[h2].h=y1;a[h2].t=1;h2++;
a[h2].x1=x1,a[h2].x2=x2,a[h2].h=y2;a[h2].t=-1;h2++;
xx[h1++]=x1,xx[h1++]=x2;
}
sort(xx,xx+h1);
int m = unique(xx,xx+h1)-xx;
for(int i=0;iif(a[i].x1>a[i].x2) swap(a[i].x1,a[i].x2);
}
sort(a,a+h2,cmp);
sert(1,1,m,a[0].x1+1,a[0].x2,a[0].t);
double ans = 0;
for(int i=1;i1,1,m);
ans += v[1]*(a[i].h-a[i-1].h);
sert(1,1,m,a[i].x1+1,a[i].x2,a[i].t);
}
printf("Test case #%d\n",++k);
printf("Total explored area: %.2f\n\n",ans);
}
return 0;
}
求面积的交,
HDU 1255
题意:给一些矩形,求这些矩形的重叠部分和.
分析:和前面面积的并差不多,就计算f[i]>=2时的面积就行了
using namespace std;
const int maxn = 1005;
double len[maxn<<3];
int f[maxn<<3];
struct edge
{
double x1,x2;
double h;
int f;
}e[maxn<<1];
double x[maxn<<1];
bool cmp(edge e1,edge e2)
{
return e1.hvoid down(int i,int l,int r,int mid)
{
f[i<<1]+=f[i];
f[i<<1|1]+=f[i];
f[i]=0;
}
void sert(int i,int a,int b,int f1,int l,int r)
{
if(a==l&&b==r)
{
f[i]+=f1;
if(f[i]>1) len[i]=x[r]-x[l-1];
else len[i]=0;
return ;
}
int mid=(l+r)>>1;
if(f[i]) down(i,l,l,mid);
if(b<=mid) sert(i<<1,a,b,f1,l,mid);
else if(a>=mid+1) sert(i<<1|1,a,b,f1,mid+1,r);
else {
sert(i<<1,a,mid,f1,l,mid);
sert(i<<1|1,mid+1,b,f1,mid+1,r);
}
}
void update(int i,int l,int r)
{
if(l==r) {
if(f[i]>=2) len[i]=x[r]-x[l-1];//这里不要忘记啦
else len[i]=0;
return ;
}
int mid = (l+r)>>1;
if(f[i]) down(i,l,l,mid);
update(i<<1,l,mid);
update(i<<1|1,mid+1,r);
if(f[i]<2)
len[i]=len[i<<1]+len[i<<1|1];
else len[i]=x[r]-x[l-1];
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(f,0,sizeof(f));
memset(e,0,sizeof(e));
memset(x,0,sizeof(x));
memset(len,0,sizeof(len));
int n;
scanf("%d",&n);
int h=0,k=0;
for(int i=0;idouble x1,y1,x2,y2;
scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
e[h].x1=x1,e[h].x2=x2,e[h].h=y1,e[h].f=1;h++;
e[h].x1=x1,e[h].x2=x2,e[h].h=y2,e[h].f=-1;h++;
x[k++]=x1,x[k++]=x2;
}
sort(x,x+k);
k=unique(x,x+k)-x;
sort(e,e+h,cmp);
double ans=0;
for(int i=0;iint l=lower_bound(x,x+k,e[i].x1)-x;
int r=lower_bound(x,x+k,e[i].x2)-x;
sert(1,l+1,r,e[i].f,1,k);
update(1,1,k);
if(i!=h-1)
ans+=len[1]*(e[i+1].h-e[i].h);
}
printf("%.2f\n",ans);
}
return 0;
}
求周长的话,感觉有两种方法,第一种是先往y轴正方向扫,从上往下,计算改变的长度,这个就是周长中横线的答案,然后往x轴正方向扫,从左往右,计算改变的长度,这个就是周长中竖线长度。
第二种方法只用扫一遍,从上往下扫,那么横线长度就是改变的长度,竖线长度就是高度2有几段横线,那么就需要维护一下横线的长度,对每个区间维护一个可以到达的左端点和右端点,然后每次合并的时候注意一下就行了。