F - City Park Gym - 100783F 计算几何+并查集



题意:

给出许多个矩形,不重叠

问连通的矩阵块面积最大是多少

题解:

因为没有重叠的,所以我们可以分别对水平线和垂直线进行并查集合并

这里我犯了一个并查集的错误,就是在累加面积的时候写反了

void Unite(int num1,int num2)
{
    int tx=find_it(num1);
    int ty=find_it(num2);
    if(tx!=ty){
        father[tx]=ty;
        sum[ty]+=sum[tx];
    }
}
上面写成了sum【tx】+=sum【ty】了导致错误

这里还需注意的是,处理同一水平线上的线段要注意大小关系

两份代码,供参考


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

#define MAXN 100050
#define LL long long
int father[MAXN];
LL sum[MAXN];
struct Point
{
    int x,y;
};
struct Line
{
    Point p1,p2;
    int pos;
}a[MAXN<<1],b[MAXN<<1];

int cmp1(Line A,Line B)
{
    if(A.p1.y==B.p1.y)
        return A.p1.x < B.p1.x;
    return A.p1.y < B.p1.y;
}
int cmp2(Line A,Line B)
{
    if(A.p1.x==B.p1.x)
        return A.p1.y < B.p1.y;
    return A.p1.x < B.p1.x;
}

int find_it(int x)
{
    int tempx=x,t;
    while(tempx!=father[tempx])
        tempx=father[tempx];
    while(x!=father[x])
    {
        t=father[x];
        father[x]=tempx;
        x=t;
    }
    return tempx;
}

void Unite(int num1,int num2)
{
    int tx=find_it(num1);
    int ty=find_it(num2);
    if(tx!=ty){
        father[tx]=ty;
        sum[ty]+=sum[tx];
    }
}

int main()
{
    int n;
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        int x,y,w,h;
        memset(sum,0,sizeof(sum));
        for(int i=0;i<n;i++){
            scanf("%d%d%d%d",&x,&y,&w,&h);
            ///水平线段
            a[i*2].p1.x=x  ,  a[i*2].p1.y=y;
            a[i*2].p2.x=x+w,  a[i*2].p2.y=y;        a[i*2].pos=i;

            a[i*2+1].p1.x=x  ,  a[i*2+1].p1.y=y+h;
            a[i*2+1].p2.x=x+w,  a[i*2+1].p2.y=y+h;  a[i*2+1].pos=i;
            ///垂直线段
            b[i*2].p1.x=x  ,  b[i*2].p1.y=y;        b[i*2].pos=i;
            b[i*2].p2.x=x  ,  b[i*2].p2.y=y+h;

            b[i*2+1].p1.x=x+w,  b[i*2+1].p1.y=y;    b[i*2+1].pos=i;
            b[i*2+1].p2.x=x+w,  b[i*2+1].p2.y=y+h;

            sum[i]=w*h;
        }

        for(int i=0;i<=n;i++)
            father[i]=i;
        sort(a,a+n*2,cmp1);
        sort(b,b+n*2,cmp2);

        int last_x=a[0].p2.x,ty=a[0].p2.y;
        int last_y=b[0].p2.y,tx=b[0].p2.x;
        for(int i=1;i<n*2;i++){
            if(a[i].p1.y==a[i-1].p1.y){
                if(a[i].p1.y!=ty){
                    last_x=a[i-1].p2.x;
                    ty=a[i].p1.y;
                }
                if(last_x>=a[i].p1.x)
                    Unite(a[i-1].pos,a[i].pos);
                last_x=last_x>a[i].p2.x?last_x:a[i].p2.x;
            }
            if(b[i].p1.x==b[i-1].p1.x){
                if(tx!=b[i].p1.x){
                    tx=b[i].p1.x;
                    last_y=b[i-1].p2.y;
                }
                if(last_y>=b[i].p1.y)
                    Unite(b[i-1].pos,b[i].pos);
                last_y=last_y>b[i].p2.y?last_y:b[i].p2.y;
            }
        }
        LL ans=0;
        for(int i=0;i<n;i++)
            ans=ans>sum[i]?ans:sum[i];
        printf("%lld\n",ans);
    }
    return 0;
}




#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

#define MAXN 100050
#define LL long long
int father[MAXN];
int sum[MAXN];
int W[MAXN],H[MAXN];
struct Line
{
    int x,l,r,id;
    Line(int x=0,int l=0,int r=0,int id=0):x(x),l(l),r(r),id(id){}
    bool operator < (const Line &b)const{
        return x<b.x||(x==b.x&&l<b.l)||(x==b.x&&l==b.l&&r<b.r);
    }
};
Line a[MAXN*3],b[MAXN*3];

int find_it(int x)
{
    if(father[x]!=x) father[x]=find_it(father[x]);
    return father[x];
}

int main()
{
    int n;
    //freopen("in.txt","r",stdin);
    while(scanf("%d",&n)!=EOF)
    {
        int x,y,w,h;
        memset(sum,0,sizeof(sum));
        for(int i=0;i<n;i++){
            scanf("%d%d%d%d",&x,&y,&w,&h);
            ///水平线段
            a[i]=Line(y,x,x+w,i);
            a[i+n]=Line(y+h,x,x+w,i);
            ///垂直线段
            b[i]=Line(x,y,y+h,i);
            b[i+n]=Line(x+w,y,y+h,i);

            W[i]=w;
            H[i]=h;
            father[i]=i;
        }

        int m=n<<1;
        sort(a,a+m);
        sort(b,b+m);
        for(int i=0;i<m;){
            int j=i,mx=a[i].r;
            while(j<=m&&a[j].x==a[i].x)
            {
                if(a[j].l<=mx){
                    int tx=find_it(a[j].id);
                    int ty=find_it(a[i].id);
                    if(tx!=ty)
                        father[tx]=ty;
                    mx=max(mx,a[j].r);
                    j++;
                }
                else
                    break;
            }
            i=j;
        }
        for(int i=0;i<m;){
            int j=i,mx=b[i].r;
            while(j<=m&&b[j].x==b[i].x)
            {
                if(b[j].l<=mx){
                    int tx=find_it(b[j].id);
                    int ty=find_it(b[i].id);
                    if(tx!=ty)
                        father[tx]=ty;
                    mx=max(mx,b[j].r);
                    j++;
                }
                else
                    break;
            }
            i=j;
        }
        int ans=0;
        int t;
        for(int i=0;i<n;i++){
            t=find_it(i);
            sum[t]+=W[i]*H[i];
            ans=max(ans,sum[t]);
        }
        printf("%d\n",ans);
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值