HDU 1542
HDU 1255
HDU 3642
#include<bits/stdc++.h>
using namespace std;
const int N=210;
int cnt[N<<2];double sum[N<<2],X[N];
struct seg{
double h,l,r;int s;
seg(){
}
seg(double a,double b,double c,int s):l(a),r(b),h(c),s(s){
}
bool operator <(const seg &x) const
{
return h<x.h ;
}//高度从下往上
}ss[N];
void up(int rt,int l,int r)
{
if(cnt[rt]) sum[rt]=X[r+1]-X[l];//如果依然采用sum相加 会漏掉mid --mid+1这个一区间
else if(l==r) sum[rt]=0;
else sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&R>=r)
{
cnt[rt]+=c;
up(rt,l,r);
return ;
}
int m=(l+r)>>1;
if(L<=m) update(L,R,c,l,m,rt<<1);
if(m<R) update(L,R,c,m+1,r,rt<<1|1);
up(rt,l,r);
}
int main()
{
int cas=1;int n ;
while(~scanf("%d",&n),n)
{
int m=0 ;
while(n--)
{
double a,b,c,d;
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
X[m]=a;ss[m++]=seg(a,c,b,1);//左端点,右端点,高度,上下底边
X[m]=c;ss[m++]=seg(a,c,d,-1);
}
sort(X,X+m);
sort(ss,ss+m);
int k=unique (X,X+m)-X;
memset(cnt,0,sizeof(cnt));
memset(sum,0,sizeof(sum));
double ret=0;
for(int i=0;i<m-1;i++)
{
int l=lower_bound(X,X+k,ss[i].l )-X;
int r=lower_bound(X,X+k,ss[i].r )-X-1;//!!!注意考虑右端点要-1
update(l,r,ss[i].s ,0,k-1,1);//更新底边长
ret+=sum[1]*(ss[i+1].h -ss[i].h );
}
printf("Test case #%d\n",cas++);
printf("Total explored area: %.2f\n\n",ret);
}
}
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
double sum[N<<3],one[N<<3],x[N];int cnt[N<<3];//注意空间开大8倍
//题目要求被覆盖两次及以上的平面的面积 同之前的面积并比较我们需要收集的sum必须是该区间内覆盖次数大于2 的线段长度
struct node
{
double l,r,h;int s;
node(){
}
node(double a,double b,double c,int d) :l(a),r(b),h(c),s(d){
}
bool operator <(const node &x ) const
{
return h<x.h ;
}
}seg[N];
void up(int rt,int l,int r)
{
if(cnt[rt]>=2) //cnt表示区间被覆盖的次数
{
sum[rt]=x[r+1]-x[l];//区间覆盖次数大于2
one[rt]=0;//one 表示该区间中被覆盖一次的长度
}
if(cnt[rt]==1)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1]+one[rt<<1]+one[rt<<1|1];
//区间覆盖次数为1 区间中被覆盖两次以上的长度就是之前 被覆盖两次以上的长度+之前被覆盖一次的长度(因为之前覆盖了一次加上现在覆盖次数就是两次了
one[rt]=x[r+1]-x[l]-sum[rt];//等于完全覆盖-被覆盖两次以上的区间长度
}
if(cnt[rt]==0)//区间目前的覆盖次数是0
{
sum[rt]=sum[rt<<1|1]+sum[rt<<1];//现在该区间被覆盖两次的长度等于之前被覆盖两次的长度
one[rt]=one[rt<<1]+one[rt<<1|1];//同
}
}
void update(int rt,int L,int R,int l,int r,int v)
{
if(L<=l&&R>=r)
{
cnt[rt]+=v;
up(rt,l,r);return ;
}
int mid=(l+r)>>1;
if(L<=mid) update(rt<<1,L,R,l,mid,v);
if(R>mid) update(rt<<1|1,L,R,mid+1,r,v);
up(rt,l,r);
}
int main()
{
int tt;scanf("%d",&tt);
while(tt--)
{
int n,m=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
double a,b,c,d;
scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
x[m]=a;
seg[m++]=node(a,c,b,1);
x[m]=c;
seg[m++]=node(a,c,d,-1);
}
sort(x,x+m);
sort(seg,seg+m);
memset(sum,0,sizeof(sum));
memset(cnt,0,sizeof(cnt));
memset(one,0,sizeof(one));
int k=unique(x,x+m)-x;double res=0;
for(int i=0;i<m-1;i++)
{
int l=lower_bound(x,x+k,seg[i].l)-x;
int r=lower_bound(x,x+k,seg[i].r)-x-1;
update(1,l,r,0,k-1,seg[i].s );
res+=sum[1]*(seg[i+1].h -seg[i].h);
}
printf("%.2lf\n",res);
}
}
扫描线算法求三维空间重叠三次及以上部分的体积
LINK
#include<bits/stdc++.h>
using namespace std;
const int N=2010;
typedef long long ll;
int x[N],z[N];
int xx,zz,n;int cas=0;
int cnt[N<<3],one[N<<3],two[N<<3],sum[N<<3];
//题目要求求空间中重叠超过三次的部分的体积
//idea:把x z 离散化求 面积(重叠超过三次的部分)乘以高度
//cnt表示某一个区间内的覆盖次数
//one表示这个区间被覆盖了一次的线段的长度
//two 表示这个区间中被覆盖两次的线段的长度
//sum表示这个区间中被覆盖三次的长度
struct node
{
int l,r,h,s;
node(){
}
node (int l,int r,int h,int s):l(l),r(r),h(h),s(s){
}
operator <(const node &x) const
{
return h<x.h;
}
}seg[N];
struct po
{
int x,y,z;
void read()
{
scanf("%d%d%d",&x,&y,&z);
}
};
struct cube{
po a,b;
}A[N];
void up(int rt,int l,int r)//想法的其实和上面第二题很像
{
if(cnt[rt]>=3)
{
sum[rt]=x[r+1]-x[l];
two[rt]=0;
one[rt]=0;
return ;
}
if(cnt[rt]==2)
{
sum[rt]=sum[rt<<1|1]+sum[rt<<1]+one[rt<<1|1]+one[rt<<1]+two[rt<<1|1]+two[rt<<1];
one[rt]=0;
two[rt]=x[r+1]-x[l]-sum[rt];
return ;
}
if(cnt[rt]==1)
{
sum[rt]=sum[rt<<1|1]+sum[rt<<1]+two[rt<<1|1]+two[rt<<1];
two[rt]=one[rt<<1|1]+one[rt<<1];
one[rt]=x[r+1]-x[l]-sum[rt]-two[rt];
return ;
}
if(cnt[rt]==0)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
two[rt]=two[rt<<1]+two[rt<<1|1];
one[rt]=one [rt<<1]+one[rt<<1|1];
return ;
}
}
void update(int rt,int l,int r,int L,int R,int v)
{
if(L<=l&&R>=r)
{
cnt[rt]+=v;
up(rt,l,r);
return ;
}
int mid=(l+r)>>1;
if(L<=mid) update(rt<<1,l,mid,L,R,v);
if(R>mid) update(rt<<1|1,mid+1,r,L,R,v);
up(rt,l,r);
}
void deal()
{
sort(x,x+xx);
sort(z,z+zz);
xx=unique(x,x+xx)-x;
zz=unique(z,z+zz)-z;
ll ans=0;
for(int i=0;i<zz-1;i++)
{
int tot=0;
for(int j=1;j<=n;j++)
{
if(A[j].a.z<=z[i]&&A[j].b.z>z[i])
{
int x1=A[j].a.x,x2=A[j].b.x;
int y1=A[j].a.y,y2=A[j].b.y;
seg[tot++]=node(x1,x2,y1,1);
seg[tot++]=node(x1,x2,y2,-1);
}
}
memset(cnt,0,sizeof(cnt));
memset(one,0,sizeof(one));
memset(two,0,sizeof(two));
memset(sum,0,sizeof(sum));
sort(seg,seg+tot);
ll s=0;
for(int j=0;j<tot-1;j++)
{
int l=lower_bound(x,x+xx,seg[j].l )-x;
int r=lower_bound(x,x+xx,seg[j].r )-x-1;
update(1,0,xx-1,l,r,seg[j].s ) ;
s+=(ll)sum[1]*(seg[j+1].h-seg[j].h );
}
ans+=s*(z[i+1]-z[i]);
}
printf("Case %d: %lld\n",++cas,ans);
}
int main()
{
int tt;scanf("%d",&tt);
while(tt--)
{
scanf("%d",&n);
xx=0;
zz=0;
for(int i=1;i<=n;i++)
{
A[i].a.read();
A[i].b.read();
x[xx++]=A[i].a.x;
x[xx++]=A[i].b.x;
z[zz++]=A[i].a.z;
z[zz++]=A[i].b.z;
}
if(n<3)
{
printf("Case %d: 0\n",++cas);
}else
{
deal();
}
}
}