线段树(扫描线)求面积并, 交以及周长

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.h<a2.h;
}
double 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;i<h2;i++){
            a[i].x1=lower_bound(xx,xx+m,a[i].x1)-xx;
            a[i].x2=lower_bound(xx,xx+m,a[i].x2)-xx;
            if(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;i<h2;i++){
            update(1,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.h<e2.h;
}
void 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;i<n;i++)
        {
            double 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;i<h;i++)
        {
            int 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有几段横线,那么就需要维护一下横线的长度,对每个区间维护一个可以到达的左端点和右端点,然后每次合并的时候注意一下就行了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值