CSU2020:Artwork(并查集)

题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=2022

题目:
Description
A template for an artwork is a white grid of n × m squares. The artwork will be created by painting q horizontal and vertical black strokes. A stroke starts from square (x1, y1), ends at square (x2,y2)(x1=x2 or y1=y2) and changes the color of all squares (x, y) to black where x1 ≤ x ≤ x2 and y1 ≤ y ≤ y2. The beauty of an artwork is the number of regions in the grid. Each region consists of one or more white squares that are connected to each other using a path of white squares in the grid, walking horizontally or vertically but not diagonally. The initial beauty of the artwork is 1. Your task is to calculate the beauty after each new stroke. Figure A.1 illustrates how the beauty of the artwork varies in Sample Input 1.

这里写图片描述

Input
The first line of input contains three integers n, m and q (1 ≤ n, m ≤ 1000, 1 ≤ q ≤ 104). Then follow q lines that describe the strokes. Each line consists of four integersx1,y1,x2 and y2(1 ≤ x1 ≤ x2 ≤ n, 1 ≤ y1 ≤ y2 ≤ m). Either x1 = x2 or y1=y2(or both).

Output
For each of the q strokes, output a line containing the beauty of the artwork after the stroke.

Sample Input
4 6 5
2 2 2 6
1 3 4 3
2 5 3 5
4 6 4 6
1 6 4 6
Sample Output
1
3
3
4
3
Hint
Source
NCPC 2016

题意: 首先给你一个n*m大小的图,有几个查询,每个查询,会输入两个在一条直线上的点(可以是同一个点),这两个点之间的点和自己会被染色,然后求没有被染色的连通的区域有多少个,前面被染色的点,后面还是在其它查询里还是会存在。

思路: 首先储存好所有的查询,并把所有查询中要染色的点 全部染色,然后从最后一个查询开始反向遍历,让查询中 被染色的点变为不染色,并把此时的连通区域存起来。使用并查集处理连通区域很方便。 因为这个图的坐标x,y值是相反的,很不适应,我就把所有格子从左上到右下从数字1开始标记,直到n*m。

代码:

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

const int maxn =10000+5;
const int maxn1 =1000000+5;
int vis[maxn1];//标记数组
int fa[maxn1],son[maxn1];
int n,m,q,cnt,ans;

int find_(int x)
{
    return x==fa[x]? x: x=find_(fa[x]);
}

struct query//几次查询染色
{
    int x,y,x1,y1,sum;//染色的起点坐标和终点坐标、答案。

} Q[maxn];


void solve(int a,int b)
{
    int x,y;
    x=find_(a);
    y=find_(b);
    if(x==y)
        return;
    ans--;
    if(son[x]>son[y])
    {
        fa[y]=x;
        son[x]+=son[y];
    }
    else
    {
        fa[x]=y;
        son[y]+=son[x];
    }
}

void union_(int i)
{
    ans++;
    son[i]=1;
    if(i+1<=n*m&&vis[i+1]==0)
    {

        if(i%n!=0)
            solve(i,i+1);
    }
    if(i-1>=1&&vis[i-1]==0)
    {

        if(i%n!=1)
            solve(i-1,i);
    }
    if(i+n<=n*m&&vis[i+n]==0)
    {


        solve(i,i+n);
    }
    if(i-n>=1&&vis[i-n]==0)
    {


        solve(i-n,i);
    }
    return;
}

int main()
{
    // freopen("in.txt","r",stdin);
    while(scanf("%d%d%d",&n,&m,&q)!=EOF)
    {
        memset(son,0,sizeof(son));
        cnt=0;
        ans=0;
        for(int i=1; i<=n*m; i++)
        {
            vis[i]=0;
            fa[i]=i;
        }
        for(int i=1; i<=q; i++)
        {
            scanf("%d%d%d%d",&Q[i].x,&Q[i].y,&Q[i].x1,&Q[i].y1);
            Q[i].sum=0;
            if(Q[i].x==Q[i].x1)
            {
                for(int j=(Q[i].y-1)*n+Q[i].x; j<=(Q[i].y1-1)*n+Q[i].x1; j+=n)
                    vis[j]++;//一个格子可以多次被染色,所以我标记一下,当vis==0时,证明没有被染色了。
            }
            else if(Q[i].y==Q[i].y1)
            {
                for(int j=(Q[i].y-1)*n+Q[i].x; j<=(Q[i].y1-1)*n+Q[i].x1; j++)
                    vis[j]++;
            }

        }

        for(int i=1; i<=n*m; i++)
        {
            if(vis[i]==0)
                union_(i);
        }
        Q[q].sum=ans;
        for(int i=q; i>=2; i--)
        {

            if(Q[i].x==Q[i].x1)
            {
                for(int j=(Q[i].y-1)*n+Q[i].x; j<=(Q[i].y1-1)*n+Q[i].x1; j+=n)
                    vis[j]--;
                for(int j=(Q[i].y-1)*n+Q[i].x; j<=(Q[i].y1-1)*n+Q[i].x1; j+=n)
                {
                    if(vis[j]==0)
                        union_(j);
                }

            }
            else if(Q[i].y==Q[i].y1)
            {
                for(int j=(Q[i].y-1)*n+Q[i].x; j<=(Q[i].y1-1)*n+Q[i].x1; j++)
                    vis[j]--;
                for(int j=(Q[i].y-1)*n+Q[i].x; j<=(Q[i].y1-1)*n+Q[i].x1; j++)
                {
                    if(vis[j]==0)
                        union_(j);
                }

            }
            cnt++;
            Q[q-cnt].sum=ans;
        }
        for(int i=q-cnt; i<=q; i++)
            printf("%d\n",Q[i].sum);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值